blob: 8367f169afb2f9dd9c576274ff3078fb3498ae22 [file] [log] [blame]
Jonathan Hart062a2e82014-02-03 09:41:57 -08001package net.onrc.onos.ofcontroller.networkgraph;
2
Yuta HIGUCHI1c700102014-02-12 16:30:52 -08003import java.net.InetAddress;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08004import java.util.ArrayList;
5import java.util.HashSet;
6import java.util.List;
7import java.util.Set;
8
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -08009import net.onrc.onos.datastore.topology.RCLink;
Jonathan Hart062a2e82014-02-03 09:41:57 -080010import net.onrc.onos.datastore.topology.RCPort;
11import net.onrc.onos.datastore.topology.RCSwitch;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080012import net.onrc.onos.ofcontroller.networkgraph.PortEvent.SwitchPort;
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080013import net.onrc.onos.ofcontroller.util.Dpid;
Jonathan Hart062a2e82014-02-03 09:41:57 -080014
15import org.slf4j.Logger;
16import org.slf4j.LoggerFactory;
17
18import edu.stanford.ramcloud.JRamCloud.ObjectDoesntExistException;
19
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080020/**
21 * The "NB" read-only Network Map.
22 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080023 * - Maintain Invariant/Relationships between Topology Objects.
24 *
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080025 * TODO To be synchronized based on TopologyEvent Notification.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080026 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080027 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080028 * Object must exist before adding sub component(Add Switch -> Port).
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080029 *
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
Yuta HIGUCHI1c700102014-02-12 16:30:52 -0800377 Device device = getDeviceByMac(deviceEvt.getMac());
378 if ( device == null ) {
379 device = new DeviceImpl(this, deviceEvt.getMac());
380 Device existing = mac2Device.putIfAbsent(deviceEvt.getMac(), device);
381 if (existing != null) {
382 log.warn(
383 "Concurrent putDevice seems to be in action. Continuing updating {}",
384 existing);
385 device = existing;
386 }
387 }
388 DeviceImpl memDevice = getDeviceImpl(device);
389
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800390 // for each attachment point
Yuta HIGUCHI1c700102014-02-12 16:30:52 -0800391 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
392 // Attached Ports' Parent Switch must exist
393 Switch sw = getSwitch(swp.dpid);
394 if ( sw == null ) {
395 log.warn("Switch {} for the attachment point did not exist. skipping mutation", sw);
396 continue;
397 }
398 // Attached Ports must exist
399 Port port = sw.getPort(swp.number);
400 if ( port == null ) {
401 log.warn("Port {} for the attachment point did not exist. skipping mutation", port);
402 continue;
403 }
404 // Attached Ports must not have Link
405 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
406 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.", port.getOutgoingLink(), port.getIncomingLink());
407 continue;
408 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800409
Yuta HIGUCHI1c700102014-02-12 16:30:52 -0800410 // finally add Device <-> Port on In-memory structure
411 PortImpl memPort = getPortImpl(port);
412 memPort.addDevice(device);
413 memDevice.addAttachmentPoint(port);
414 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800415
Yuta HIGUCHI1c700102014-02-12 16:30:52 -0800416 // for each IP address
417 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
418 // Add Device -> IP
419 memDevice.addIpAddress(ipAddr);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800420
Yuta HIGUCHI1c700102014-02-12 16:30:52 -0800421 // Add IP -> Set<Device>
422 boolean updated = false;
423 do {
424 Set<Device> devices = this.addr2Device.get(ipAddr);
425 if ( devices == null ) {
426 devices = new HashSet<>();
427 Set<Device> existing = this.addr2Device.putIfAbsent(ipAddr, devices);
428 if ( existing == null ) {
429 // success
430 updated = true;
431 }
432 } else {
433 Set<Device> updateDevices = new HashSet<>(devices);
434 updateDevices.add(device);
435 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
436 }
437 if (!updated) {
438 log.debug("Collision detected, updating IP to Device mapping retrying.");
439 }
440 } while( !updated );
441 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800442 }
443
Yuta HIGUCHI1c700102014-02-12 16:30:52 -0800444 void removeDevice(DeviceEvent deviceEvt) {
445 if (deviceEvt == null) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800446 throw new IllegalArgumentException("Device cannot be null");
447 }
Yuta HIGUCHI1c700102014-02-12 16:30:52 -0800448
449 Device device = getDeviceByMac(deviceEvt.getMac());
450 if ( device == null ) {
451 log.warn("Device {} already removed, ignoring", deviceEvt);
452 return;
453 }
454 DeviceImpl memDevice = getDeviceImpl(device);
455
456 // for each attachment point
457 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
458 // Attached Ports' Parent Switch must exist
459 Switch sw = getSwitch(swp.dpid);
460 if ( sw == null ) {
461 log.warn("Switch {} for the attachment point did not exist. skipping mutation", sw);
462 continue;
463 }
464 // Attached Ports must exist
465 Port port = sw.getPort(swp.number);
466 if ( port == null ) {
467 log.warn("Port {} for the attachment point did not exist. skipping mutation", port);
468 continue;
469 }
470
471 // finally remove Device <-> Port on In-memory structure
472 PortImpl memPort = getPortImpl(port);
473 memPort.removeDevice(device);
474 memDevice.removeAttachmentPoint(port);
475 }
476
477 // for each IP address
478 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
479 // Remove Device -> IP
480 memDevice.removeIpAddress(ipAddr);
481
482 // Remove IP -> Set<Device>
483 boolean updated = false;
484 do {
485 Set<Device> devices = this.addr2Device.get(ipAddr);
486 if ( devices == null ) {
487 // already empty set, nothing to do
488 updated = true;
489 } else {
490 Set<Device> updateDevices = new HashSet<>(devices);
491 updateDevices.remove(device);
492 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
493 }
494 if (!updated) {
495 log.debug("Collision detected, updating IP to Device mapping retrying.");
496 }
497 } while( !updated );
498 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800499 }
500
501 private SwitchImpl getSwitchImpl(Switch sw) {
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800502 if (sw instanceof SwitchImpl) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800503 return (SwitchImpl) sw;
504 }
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800505 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
506 }
507
508 private PortImpl getPortImpl(Port p) {
509 if (p instanceof PortImpl) {
510 return (PortImpl) p;
511 }
512 throw new ClassCastException("PortImpl expected, but found: " + p);
513 }
514
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800515 private LinkImpl getLinkImpl(Link l) {
516 if (l instanceof LinkImpl) {
517 return (LinkImpl) l;
518 }
519 throw new ClassCastException("LinkImpl expected, but found: " + l);
520 }
521
Yuta HIGUCHIc0366272014-02-10 21:04:57 -0800522 private DeviceImpl getDeviceImpl(Device d) {
523 if (d instanceof DeviceImpl) {
524 return (DeviceImpl) d;
525 }
526 throw new ClassCastException("DeviceImpl expected, but found: " + d);
527 }
528
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800529 public void loadWholeTopologyFromDB() {
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800530 // TODO this method needs to use East-bound API if we still need this
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800531 // XXX clear everything first?
532
533 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
534 try {
535 sw.read();
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800536 // TODO if there is going to be inactive Switch in DB, skip
537 // TODO update other attributes if there exist any
538 putSwitch(new SwitchEvent(sw.getDpid()));
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800539 } catch (ObjectDoesntExistException e) {
540 log.error("Read Switch Failed, skipping", e);
541 }
542 }
543
544 for (RCPort p : RCPort.getAllPorts()) {
545 try {
546 p.read();
547
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800548 Switch sw = this.getSwitch(p.getDpid());
549 if (sw == null) {
550 log.error("Switch {} missing when adding Port {}",
551 new Dpid(p.getDpid()), p);
552 continue;
553 }
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800554 PortEvent portEvent = new PortEvent(p.getDpid(), p.getNumber());
555 // TODO update other attributes if there exist any
556 putPort(portEvent);
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800557 } catch (ObjectDoesntExistException e) {
558 log.error("Read Port Failed, skipping", e);
559 }
560 }
561
562 // TODO Is Device going to be in DB? If so, read from DB.
563 // for (RCDevice d : RCDevice.getAllDevices()) {
564 // try {
565 // d.read();
566 //
567 // } catch (ObjectDoesntExistException e) {
568 // log.debug("Read Device Failed, skipping", e);
569 // }
570 // }
571
572 for (RCLink l : RCLink.getAllLinks()) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800573 try {
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800574 l.read();
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800575
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800576 Switch srcSw = this.getSwitch(l.getSrc().dpid);
577 if (srcSw == null) {
578 log.error("Switch {} missing when adding Link {}",
579 new Dpid(l.getSrc().dpid), l);
580 continue;
581 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800582
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800583 Switch dstSw = this.getSwitch(l.getDst().dpid);
584 if (dstSw == null) {
585 log.error("Switch {} missing when adding Link {}",
586 new Dpid(l.getDst().dpid), l);
587 continue;
588 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800589
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800590 LinkEvent linkEvent = new LinkEvent(l.getSrc().dpid,
591 l.getSrc().number, l.getDst().dpid, l.getDst().number);
592 // TODO update other attributes if there exist any
593 putLink(linkEvent);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800594 } catch (ObjectDoesntExistException e) {
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800595 log.debug("Delete Link Failed", e);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800596 }
Jonathan Hart062a2e82014-02-03 09:41:57 -0800597 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800598 }
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800599
600 /**
601 * Exception to be thrown when Modification to the Network Graph cannot be continued due to broken invariant.
602 *
603 * XXX Should this be checked exception or RuntimeException
604 */
605 public static class BrokenInvariantException extends RuntimeException {
606 private static final long serialVersionUID = 1L;
607
608 public BrokenInvariantException() {
609 super();
610 }
611
612 public BrokenInvariantException(String message) {
613 super(message);
614 }
615 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800616
617 /* ******************************
618 * NetworkGraphDiscoveryInterface methods
619 * ******************************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800620
Jonathan Hart22eb9882014-02-11 15:52:59 -0800621 @Override
622 public void putSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800623 if (prepareForAddSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800624 datastore.addSwitch(switchEvent);
625 putSwitch(switchEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800626 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -0800627 }
628 // TODO handle invariant violation
629 }
630
631 @Override
632 public void removeSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800633 if (prepareForRemoveSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800634 datastore.deactivateSwitch(switchEvent);
635 removeSwitch(switchEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800636 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -0800637 }
638 // TODO handle invariant violation
639 }
640
641 @Override
642 public void putPortEvent(PortEvent portEvent) {
643 // TODO Auto-generated method stub
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800644
Jonathan Hart22eb9882014-02-11 15:52:59 -0800645 }
646
647 @Override
648 public void removePortEvent(PortEvent portEvent) {
649 // TODO Auto-generated method stub
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800650
Jonathan Hart22eb9882014-02-11 15:52:59 -0800651 }
652
653 @Override
654 public void putLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800655 if (prepareForAddLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800656 datastore.addLink(linkEvent);
657 putLink(linkEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800658 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -0800659 }
660 // TODO handle invariant violation
661 }
662
663 @Override
664 public void removeLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800665 if (prepareForRemoveLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800666 datastore.removeLink(linkEvent);
667 removeLink(linkEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800668 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -0800669 }
670 // TODO handle invariant violation
671 }
672
673 @Override
Yuta HIGUCHI0be4a662014-02-11 18:01:28 -0800674 public void putDeviceEvent(DeviceEvent device) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800675 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800676 // TODO Auto-generated method stub
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800677
Jonathan Hart22eb9882014-02-11 15:52:59 -0800678 }
679
680 @Override
681 public void removeDeviceEvent(DeviceEvent deviceEvent) {
682 // TODO Auto-generated method stub
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800683
Jonathan Hart22eb9882014-02-11 15:52:59 -0800684 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800685
Jonathan Hart22eb9882014-02-11 15:52:59 -0800686 /* *****************
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800687 * Internal methods to maintain invariants of the network graph
Jonathan Hart22eb9882014-02-11 15:52:59 -0800688 * *****************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800689
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800690 /**
691 *
692 * @param swEvt
693 * @return true if ready to accept event.
694 */
695 private boolean prepareForAddSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800696 // No show stopping precondition?
697 // Prep: remove(deactivate) Ports on Switch, which is not on event
698 removePortsNotOnEvent(swEvt);
699 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800700 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800701
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800702 private boolean prepareForRemoveSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800703 // No show stopping precondition?
704 // Prep: remove(deactivate) Ports on Switch, which is not on event
705 // XXX may be remove switch should imply wipe all ports
706 removePortsNotOnEvent(swEvt);
707 return true;
708 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800709
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800710 private void removePortsNotOnEvent(SwitchEvent swEvt) {
711 Switch sw = switches.get( swEvt.getDpid() );
712 if ( sw != null ) {
713 Set<Long> port_noOnEvent = new HashSet<>();
714 for( PortEvent portEvent : swEvt.getPorts()) {
715 port_noOnEvent.add(portEvent.getNumber());
716 }
717 // Existing ports not on event should be removed.
718 // TODO Should batch eventually for performance?
719 for( Port p : sw.getPorts() ) {
720 if ( !port_noOnEvent.contains(p.getNumber()) ) {
721 PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
722 // calling Discovery removePort() API to wipe from DB, etc.
723 removePortEvent(rmEvent);
724 }
725 }
726 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800727 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800728
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800729 private boolean prepareForAddPortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800730 // Parent Switch must exist
731 if ( getSwitch(portEvt.getDpid()) == null) {
732 return false;
733 }
734 // Prep: None
Jonathan Hart22eb9882014-02-11 15:52:59 -0800735 return true;
736 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800737
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800738 private boolean prepareForRemovePortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800739 // Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800740 Switch sw = getSwitch(portEvt.getDpid());
741 if ( sw == null ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800742 return false;
743 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800744 Port port = sw.getPort(portEvt.getNumber());
745 if ( port == null ) {
746 log.debug("Port already removed? {}", portEvt);
747 // let it pass
748 return true;
749 }
750
751 // Prep: Remove Link and Device Attachment
752 for (Device device : port.getDevices()) {
753 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
754 devEvt.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(), port.getNumber()));
755 // calling Discovery API to wipe from DB, etc.
756 removeDeviceEvent(devEvt);
757 }
758 Set<Link> links = new HashSet<>();
759 links.add(port.getOutgoingLink());
760 links.add(port.getIncomingLink());
761 for ( Link link : links) {
762 if (link == null ) {
763 continue;
764 }
765 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
766 // calling Discovery API to wipe from DB, etc.
767 removeLinkEvent(linkEvent);
768 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800769 return true;
770 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800771
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800772 private boolean prepareForAddLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800773 // Src/Dst Switch must exist
774 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
775 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
776 if ( srcSw == null || dstSw == null ) {
777 return false;
778 }
779 // Src/Dst Port must exist
780 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
781 Port dstPort = srcSw.getPort(linkEvt.getDst().number);
782 if ( srcPort == null || dstPort == null ) {
783 return false;
784 }
785
786 // Prep: remove Device attachment on both Ports
787 for (Device device : srcPort.getDevices()) {
788 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
789 devEvt.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
790 // calling Discovery API to wipe from DB, etc.
791 removeDeviceEvent(devEvt);
792 }
793 for (Device device : dstPort.getDevices()) {
794 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
795 devEvt.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(), dstPort.getNumber()));
796 // calling Discovery API to wipe from DB, etc.
797 removeDeviceEvent(devEvt);
798 }
799
800 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800801 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800802
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800803 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800804 // Src/Dst Switch must exist
805 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
806 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
807 if ( srcSw == null || dstSw == null ) {
808 return false;
809 }
810 // Src/Dst Port must exist
811 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
812 Port dstPort = srcSw.getPort(linkEvt.getDst().number);
813 if ( srcPort == null || dstPort == null ) {
814 return false;
815 }
816
817 // Prep: None
818 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800819 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800820
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800821 /**
822 *
823 * @param deviceEvt Event will be modified to remove inapplicable attachemntPoints/ipAddress
824 * @return false if this event should be dropped.
825 */
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800826 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800827 boolean preconditionBroken = false;
828 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
829 for ( PortEvent.SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800830 // Attached Ports' Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800831 Switch sw = getSwitch(swp.dpid);
832 if ( sw == null ) {
833 preconditionBroken = true;
834 failedSwitchPort.add(swp);
835 continue;
836 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800837 // Attached Ports must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800838 Port port = sw.getPort(swp.number);
839 if ( port == null ) {
840 preconditionBroken = true;
841 failedSwitchPort.add(swp);
842 continue;
843 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800844 // Attached Ports must not have Link
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800845 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
846 preconditionBroken = true;
847 failedSwitchPort.add(swp);
848 continue;
849 }
850 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800851
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800852 // Rewriting event to exclude failed attachmentPoint
853 // XXX Assumption behind this is that inapplicable device event should
854 // be dropped, not deferred. If we decide to defer Device event,
855 // rewriting can become a problem
856 List<SwitchPort> attachmentPoints = deviceEvt.getAttachmentPoints();
857 attachmentPoints.removeAll(failedSwitchPort);
858 deviceEvt.setAttachmentPoints(attachmentPoints);
859
860 if ( deviceEvt.getAttachmentPoints().isEmpty() && deviceEvt.getIpAddresses().isEmpty() ) {
861 // XXX return false to represent: Nothing left to do for this event. Caller should drop event
862 return false;
863 }
864
865 // Should we return false to tell caller that the event was trimmed?
866 // if ( preconditionBroken ) {
867 // return false;
868 // }
869
870 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800871 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800872
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800873 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800874 // No show stopping precondition?
875 // Prep: none
Jonathan Hart22eb9882014-02-11 15:52:59 -0800876 return true;
877 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800878
879 @Override
880 public void putSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800881 if (prepareForAddSwitchEvent(switchEvent)) {
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800882 putSwitch(switchEvent);
883 }
884 // TODO handle invariant violation
885 }
886
887 @Override
888 public void removeSwitchReplicationEvent(SwitchEvent switchEvent) {
889 // TODO Auto-generated method stub
890
891 }
892
893 @Override
894 public void putPortReplicationEvent(PortEvent portEvent) {
895 // TODO Auto-generated method stub
896
897 }
898
899 @Override
900 public void removePortReplicationEvent(PortEvent portEvent) {
901 // TODO Auto-generated method stub
902
903 }
904
905 @Override
906 public void putLinkReplicationEvent(LinkEvent linkEvent) {
907 // TODO Auto-generated method stub
908
909 }
910
911 @Override
912 public void removeLinkReplicationEvent(LinkEvent linkEvent) {
913 // TODO Auto-generated method stub
914
915 }
916
917 @Override
918 public void putDeviceReplicationEvent(DeviceEvent deviceEvent) {
919 // TODO Auto-generated method stub
920
921 }
922
923 @Override
924 public void removeDeviceReplicationEvent(DeviceEvent deviceEvent) {
925 // TODO Auto-generated method stub
926
927 }
Jonathan Hart062a2e82014-02-03 09:41:57 -0800928}