blob: 8df13e0f27721684346b3813e760225ecdb2154b [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
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080018/**
19 * The "NB" read-only Network Map.
20 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080021 * - Maintain Invariant/Relationships between Topology Objects.
22 *
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080023 * TODO To be synchronized based on TopologyEvent Notification.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080024 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080025 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080026 * Object must exist before adding sub component(Add Switch -> Port).
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080027 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080028 * TODO TBD: This class may delay the requested change to handle event
29 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080030 *
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080031 */
Yuta HIGUCHI928fa682014-02-11 19:07:57 -080032public class NetworkGraphImpl extends AbstractNetworkGraph implements
33 NetworkGraphDiscoveryInterface, NetworkGraphReplicationInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080034
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080035 private static final Logger log = LoggerFactory
36 .getLogger(NetworkGraphImpl.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080037
Jonathan Hart22eb9882014-02-11 15:52:59 -080038 private final NetworkGraphDatastore datastore;
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080039
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080040 public NetworkGraphImpl() {
41 super();
Jonathan Hart22eb9882014-02-11 15:52:59 -080042 datastore = new NetworkGraphDatastore(this);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080043 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080044
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080045 /**
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080046 * Exception to be thrown when Modification to the Network Graph cannot be continued due to broken invariant.
47 *
48 * XXX Should this be checked exception or RuntimeException
49 */
50 public static class BrokenInvariantException extends RuntimeException {
51 private static final long serialVersionUID = 1L;
52
53 public BrokenInvariantException() {
54 super();
55 }
56
57 public BrokenInvariantException(String message) {
58 super(message);
59 }
60 }
Jonathan Hart22eb9882014-02-11 15:52:59 -080061
62 /* ******************************
63 * NetworkGraphDiscoveryInterface methods
64 * ******************************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080065
Jonathan Hart22eb9882014-02-11 15:52:59 -080066 @Override
67 public void putSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -080068 if (prepareForAddSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -080069 datastore.addSwitch(switchEvent);
70 putSwitch(switchEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -080071 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -080072 }
73 // TODO handle invariant violation
74 }
75
76 @Override
77 public void removeSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -080078 if (prepareForRemoveSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -080079 datastore.deactivateSwitch(switchEvent);
80 removeSwitch(switchEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -080081 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -080082 }
83 // TODO handle invariant violation
84 }
85
86 @Override
87 public void putPortEvent(PortEvent portEvent) {
Jonathan Hart4c263272014-02-13 17:41:05 -080088 if (prepareForAddPortEvent(portEvent)) {
89 datastore.addPort(portEvent);
90 putPort(portEvent);
91 // TODO send out notification
92 }
Yuta HIGUCHI75c51ed2014-02-13 17:02:26 -080093 // TODO handle invariant violation
Jonathan Hart22eb9882014-02-11 15:52:59 -080094 }
95
96 @Override
97 public void removePortEvent(PortEvent portEvent) {
Jonathan Hart4c263272014-02-13 17:41:05 -080098 if (prepareForRemovePortEvent(portEvent)) {
99 datastore.deactivatePort(portEvent);
100 removePort(portEvent);
101 // TODO send out notification
102 }
Yuta HIGUCHI75c51ed2014-02-13 17:02:26 -0800103 // TODO handle invariant violation
Jonathan Hart22eb9882014-02-11 15:52:59 -0800104 }
105
106 @Override
107 public void putLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800108 if (prepareForAddLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800109 datastore.addLink(linkEvent);
110 putLink(linkEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800111 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -0800112 }
113 // TODO handle invariant violation
114 }
115
116 @Override
117 public void removeLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800118 if (prepareForRemoveLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800119 datastore.removeLink(linkEvent);
120 removeLink(linkEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800121 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -0800122 }
123 // TODO handle invariant violation
124 }
125
126 @Override
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800127 public void putDeviceEvent(DeviceEvent deviceEvent) {
128 if (prepareForAddDeviceEvent(deviceEvent)) {
129// datastore.addDevice(deviceEvent);
130 // TODO send out notification
131 }
132 // TODO handle invariant violation
133 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800134 }
135
136 @Override
137 public void removeDeviceEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800138 if (prepareForRemoveDeviceEvent(deviceEvent)) {
139// datastore.removeDevice(deviceEvent);
140 // TODO send out notification
141 }
142 // TODO handle invariant violation
143 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800144 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800145
Jonathan Hart22eb9882014-02-11 15:52:59 -0800146 /* *****************
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800147 * Internal methods to maintain invariants of the network graph
Jonathan Hart22eb9882014-02-11 15:52:59 -0800148 * *****************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800149
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800150 /**
151 *
152 * @param swEvt
153 * @return true if ready to accept event.
154 */
155 private boolean prepareForAddSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800156 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800157 // Prep: remove(deactivate) Ports on Switch, which is not on event
158 removePortsNotOnEvent(swEvt);
159 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800160 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800161
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800162 private boolean prepareForRemoveSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800163 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800164 // Prep: remove(deactivate) Ports on Switch, which is not on event
165 // XXX may be remove switch should imply wipe all ports
166 removePortsNotOnEvent(swEvt);
167 return true;
168 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800169
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800170 private void removePortsNotOnEvent(SwitchEvent swEvt) {
171 Switch sw = switches.get( swEvt.getDpid() );
172 if ( sw != null ) {
173 Set<Long> port_noOnEvent = new HashSet<>();
174 for( PortEvent portEvent : swEvt.getPorts()) {
175 port_noOnEvent.add(portEvent.getNumber());
176 }
177 // Existing ports not on event should be removed.
178 // TODO Should batch eventually for performance?
Jonathan Hart480c5572014-02-14 18:28:16 -0800179 List<Port> portsToRemove = new ArrayList<Port>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800180 for( Port p : sw.getPorts() ) {
181 if ( !port_noOnEvent.contains(p.getNumber()) ) {
Jonathan Hart480c5572014-02-14 18:28:16 -0800182 //PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
183 // calling Discovery removePort() API to wipe from DB, etc.
184 //removePortEvent(rmEvent);
185
186 // We can't remove ports here because this will trigger a remove
187 // from the switch's port list, which we are currently iterating
188 // over.
189 portsToRemove.add(p);
190 }
191 }
192 for (Port p : portsToRemove) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800193 PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
194 // calling Discovery removePort() API to wipe from DB, etc.
195 removePortEvent(rmEvent);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800196 }
197 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800198 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800199
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800200 private boolean prepareForAddPortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800201 // Parent Switch must exist
202 if ( getSwitch(portEvt.getDpid()) == null) {
203 return false;
204 }
205 // Prep: None
Jonathan Hart22eb9882014-02-11 15:52:59 -0800206 return true;
207 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800208
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800209 private boolean prepareForRemovePortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800210 // Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800211 Switch sw = getSwitch(portEvt.getDpid());
212 if ( sw == null ) {
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800213 log.debug("Switch already removed? {}", portEvt);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800214 return false;
215 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800216 Port port = sw.getPort(portEvt.getNumber());
217 if ( port == null ) {
218 log.debug("Port already removed? {}", portEvt);
219 // let it pass
220 return true;
221 }
222
223 // Prep: Remove Link and Device Attachment
224 for (Device device : port.getDevices()) {
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800225 log.debug("Removing Device {} on Port {}", device, portEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800226 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
227 devEvt.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(), port.getNumber()));
228 // calling Discovery API to wipe from DB, etc.
229 removeDeviceEvent(devEvt);
230 }
231 Set<Link> links = new HashSet<>();
232 links.add(port.getOutgoingLink());
233 links.add(port.getIncomingLink());
234 for ( Link link : links) {
235 if (link == null ) {
236 continue;
237 }
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800238 log.debug("Removing Link {} on Port {}", link, portEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800239 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
240 // calling Discovery API to wipe from DB, etc.
241 removeLinkEvent(linkEvent);
242 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800243 return true;
244 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800245
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800246 private boolean prepareForAddLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800247 // Src/Dst Switch must exist
248 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
249 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
250 if ( srcSw == null || dstSw == null ) {
251 return false;
252 }
253 // Src/Dst Port must exist
254 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Jonathan Hart4c263272014-02-13 17:41:05 -0800255 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800256 if ( srcPort == null || dstPort == null ) {
257 return false;
258 }
259
260 // Prep: remove Device attachment on both Ports
261 for (Device device : srcPort.getDevices()) {
262 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
263 devEvt.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
264 // calling Discovery API to wipe from DB, etc.
265 removeDeviceEvent(devEvt);
266 }
267 for (Device device : dstPort.getDevices()) {
268 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
269 devEvt.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(), dstPort.getNumber()));
270 // calling Discovery API to wipe from DB, etc.
271 removeDeviceEvent(devEvt);
272 }
273
274 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800275 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800276
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800277 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800278 // Src/Dst Switch must exist
279 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
280 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
281 if ( srcSw == null || dstSw == null ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800282 log.warn("Rejecting removeLink {} because switch doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800283 return false;
284 }
285 // Src/Dst Port must exist
286 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800287 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800288 if ( srcPort == null || dstPort == null ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800289 log.warn("Rejecting removeLink {} because port doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800290 return false;
291 }
292
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800293 Link link = srcPort.getOutgoingLink();
294
295 // Link is already gone, or different Link exist in memory
296 // XXX Check if we should reject or just accept these cases.
297 // it should be harmless to remove the Link on event from DB anyways
298 if (link == null ||
299 !link.getDestinationPortNumber().equals(linkEvt.getDst().number)
300 || !link.getDestinationSwitchDpid().equals(linkEvt.getDst().dpid)) {
301 log.warn("Rejecting removeLink {} because link doesn't exist", linkEvt);
302 return false;
303 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800304 // Prep: None
305 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800306 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800307
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800308 /**
309 *
310 * @param deviceEvt Event will be modified to remove inapplicable attachemntPoints/ipAddress
311 * @return false if this event should be dropped.
312 */
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800313 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800314 boolean preconditionBroken = false;
315 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
316 for ( PortEvent.SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800317 // Attached Ports' Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800318 Switch sw = getSwitch(swp.dpid);
319 if ( sw == null ) {
320 preconditionBroken = true;
321 failedSwitchPort.add(swp);
322 continue;
323 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800324 // Attached Ports must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800325 Port port = sw.getPort(swp.number);
326 if ( port == null ) {
327 preconditionBroken = true;
328 failedSwitchPort.add(swp);
329 continue;
330 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800331 // Attached Ports must not have Link
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800332 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
333 preconditionBroken = true;
334 failedSwitchPort.add(swp);
335 continue;
336 }
337 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800338
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800339 // Rewriting event to exclude failed attachmentPoint
340 // XXX Assumption behind this is that inapplicable device event should
341 // be dropped, not deferred. If we decide to defer Device event,
342 // rewriting can become a problem
343 List<SwitchPort> attachmentPoints = deviceEvt.getAttachmentPoints();
344 attachmentPoints.removeAll(failedSwitchPort);
345 deviceEvt.setAttachmentPoints(attachmentPoints);
346
347 if ( deviceEvt.getAttachmentPoints().isEmpty() && deviceEvt.getIpAddresses().isEmpty() ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800348 // return false to represent: Nothing left to do for this event. Caller should drop event
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800349 return false;
350 }
351
352 // Should we return false to tell caller that the event was trimmed?
353 // if ( preconditionBroken ) {
354 // return false;
355 // }
356
357 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800358 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800359
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800360 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800361 // No show stopping precondition?
362 // Prep: none
Jonathan Hart22eb9882014-02-11 15:52:59 -0800363 return true;
364 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800365
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800366 /* ******************************
367 * NetworkGraphReplicationInterface methods
368 * ******************************/
369
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800370 @Override
371 public void putSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800372 if (prepareForAddSwitchEvent(switchEvent)) {
373 putSwitch(switchEvent);
374 }
375 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800376 }
377
378 @Override
379 public void removeSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800380 if (prepareForRemoveSwitchEvent(switchEvent)) {
381 removeSwitch(switchEvent);
382 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800383 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800384 }
385
386 @Override
387 public void putPortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800388 if (prepareForAddPortEvent(portEvent)) {
389 putPort(portEvent);
390 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800391 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800392 }
393
394 @Override
395 public void removePortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800396 if (prepareForRemovePortEvent(portEvent)) {
397 removePort(portEvent);
398 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800399 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800400 }
401
402 @Override
403 public void putLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800404 if (prepareForAddLinkEvent(linkEvent)) {
405 putLink(linkEvent);
406 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800407 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800408 }
409
410 @Override
411 public void removeLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800412 if (prepareForRemoveLinkEvent(linkEvent)) {
413 removeLink(linkEvent);
414 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800415 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800416 }
417
418 @Override
419 public void putDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800420 if (prepareForAddDeviceEvent(deviceEvent)) {
421 putDevice(deviceEvent);
422 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800423 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800424 }
425
426 @Override
427 public void removeDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800428 if (prepareForRemoveDeviceEvent(deviceEvent)) {
429 removeDevice(deviceEvent);
430 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800431 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800432 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800433
434 /* ************************************************
435 * Internal In-memory object mutation methods.
436 * ************************************************/
437
438 void putSwitch(SwitchEvent swEvt) {
439 if (swEvt == null) {
440 throw new IllegalArgumentException("Switch cannot be null");
441 }
442
443 Switch sw = switches.get(swEvt.getDpid());
444
445 if (sw == null) {
446 sw = new SwitchImpl(this, swEvt.getDpid());
447 Switch existing = switches.putIfAbsent(swEvt.getDpid(), sw);
448 if (existing != null) {
449 log.warn(
450 "Concurrent putSwitch not expected. Continuing updating {}",
451 existing);
452 sw = existing;
453 }
454 }
455
456 // Update when more attributes are added to Event object
457 // no attribute to update for now
458
459 // TODO handle child Port event properly for performance
460 for (PortEvent portEvt : swEvt.getPorts() ) {
461 putPort(portEvt);
462 }
463
464 }
465
466 void removeSwitch(SwitchEvent swEvt) {
467 if (swEvt == null) {
468 throw new IllegalArgumentException("Switch cannot be null");
469 }
470
471 // TODO handle child Port event properly for performance
472 for (PortEvent portEvt : swEvt.getPorts() ) {
473 removePort(portEvt);
474 }
475
476 Switch sw = switches.get(swEvt.getDpid());
477
478 if (sw == null) {
479 log.warn("Switch {} already removed, ignoring", swEvt);
480 return;
481 }
482
483 // Sanity check
484 if (!sw.getPorts().isEmpty()) {
485 log.warn(
486 "Ports on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
487 swEvt);
488 // XXX Should we remove Port?
489 }
490 if (!sw.getDevices().isEmpty()) {
491 log.warn(
492 "Devices on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
493 swEvt);
494 // XXX Should we remove Device to Switch relation?
495 }
496 if (!sw.getIncomingLinks().iterator().hasNext()) {
497 log.warn(
498 "IncomingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
499 swEvt);
500 // XXX Should we remove Link?
501 }
502 if (!sw.getOutgoingLinks().iterator().hasNext()) {
503 log.warn(
504 "OutgoingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
505 swEvt);
506 // XXX Should we remove Link?
507 }
508
509 boolean removed = switches.remove(swEvt.getDpid(), sw);
510 if (removed) {
511 log.warn(
512 "Switch instance was replaced concurrently while removing {}. Something is not right.",
513 sw);
514 }
515 }
516
517 void putPort(PortEvent portEvt) {
518 if (portEvt == null) {
519 throw new IllegalArgumentException("Port cannot be null");
520 }
521 Switch sw = switches.get(portEvt.getDpid());
522 if (sw == null) {
523 throw new BrokenInvariantException(String.format(
524 "Switch with dpid %s did not exist.",
525 new Dpid(portEvt.getDpid())));
526 }
527 Port p = sw.getPort(portEvt.getNumber());
528 PortImpl port = null;
529 if (p != null) {
530 port = getPortImpl(p);
531 }
532
533 if (port == null) {
534 port = new PortImpl(this, sw, portEvt.getNumber());
535 }
536
537 // TODO update attributes
538
539 SwitchImpl s = getSwitchImpl(sw);
540 s.addPort(port);
541 }
542
543 void removePort(PortEvent portEvt) {
544 if (portEvt == null) {
545 throw new IllegalArgumentException("Port cannot be null");
546 }
547
548 Switch sw = switches.get(portEvt.getDpid());
549 if (sw == null) {
550 log.warn("Parent Switch for Port {} already removed, ignoring", portEvt);
551 return;
552 }
553
554 Port p = sw.getPort(portEvt.getNumber());
555 if (p == null) {
556 log.warn("Port {} already removed, ignoring", portEvt);
557 return;
558 }
559
560 // check if there is something referring to this Port
561
562 if (!p.getDevices().iterator().hasNext()) {
563 log.warn(
564 "Devices on Port {} should be removed prior to removing Port. Removing Port anyways",
565 portEvt);
566 // XXX Should we remove Device to Port relation?
567 }
568 if (p.getIncomingLink() != null) {
569 log.warn(
570 "IncomingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
571 portEvt);
572 // XXX Should we remove Link?
573 }
574 if (p.getOutgoingLink() != null) {
575 log.warn(
576 "OutgoingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
577 portEvt);
578 // XXX Should we remove Link?
579 }
580
581 // remove Port from Switch
582 SwitchImpl s = getSwitchImpl(sw);
583 s.removePort(p);
584 }
585
586 void putLink(LinkEvent linkEvt) {
587 if (linkEvt == null) {
588 throw new IllegalArgumentException("Link cannot be null");
589 }
590
591 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
592 if (srcSw == null) {
593 throw new BrokenInvariantException(
594 String.format(
595 "Switch with dpid %s did not exist.",
596 new Dpid(linkEvt.getSrc().dpid)));
597 }
598
599 Switch dstSw = switches.get(linkEvt.getDst().dpid);
600 if (dstSw == null) {
601 throw new BrokenInvariantException(
602 String.format(
603 "Switch with dpid %s did not exist.",
604 new Dpid(linkEvt.getDst().dpid)));
605 }
606
607 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
608 if (srcPort == null) {
609 throw new BrokenInvariantException(
610 String.format(
611 "Src Port %s of a Link did not exist.",
612 linkEvt.getSrc() ));
613 }
614
615 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
616 if (dstPort == null) {
617 throw new BrokenInvariantException(
618 String.format(
619 "Dst Port %s of a Link did not exist.",
620 linkEvt.getDst() ));
621 }
622
623 // getting Link instance from destination port incoming Link
624 Link l = dstPort.getIncomingLink();
625 LinkImpl link = null;
626 assert( l == srcPort.getOutgoingLink() );
627 if (l != null) {
628 link = getLinkImpl(l);
629 }
630
631 if (link == null) {
632 link = new LinkImpl(this, srcPort, dstPort);
633 }
634
635
636 PortImpl dstPortMem = getPortImpl(dstPort);
637 PortImpl srcPortMem = getPortImpl(srcPort);
638
639 // Add Link first to avoid further Device addition
640
641 // add Link to Port
642 dstPortMem.setIncomingLink(link);
643 srcPortMem.setOutgoingLink(link);
644
645 // remove Device Pointing to Port if any
646 for(Device d : dstPortMem.getDevices() ) {
647 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, dstPort, linkEvt);
648 DeviceImpl dev = getDeviceImpl(d);
649 dev.removeAttachmentPoint(dstPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800650 // This implies that change is made to Device Object.
651 // sending Device attachment point removed event
652 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
653 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
654 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800655 }
656 dstPortMem.removeAllDevice();
657 for(Device d : srcPortMem.getDevices() ) {
658 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, srcPort, linkEvt);
659 DeviceImpl dev = getDeviceImpl(d);
660 dev.removeAttachmentPoint(srcPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800661 // This implies that change is made to Device Object.
662 // sending Device attachment point removed event
663 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
664 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
665 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800666 }
667 srcPortMem.removeAllDevice();
668
669 }
670
671 void removeLink(LinkEvent linkEvt) {
672 if (linkEvt == null) {
673 throw new IllegalArgumentException("Link cannot be null");
674 }
675
676 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
677 if (srcSw == null) {
678 log.warn("Src Switch for Link {} already removed, ignoring", linkEvt);
679 return;
680 }
681
682 Switch dstSw = switches.get(linkEvt.getDst().dpid);
683 if (dstSw == null) {
684 log.warn("Dst Switch for Link {} already removed, ignoring", linkEvt);
685 return;
686 }
687
688 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
689 if (srcPort == null) {
690 log.warn("Src Port for Link {} already removed, ignoring", linkEvt);
691 return;
692 }
693
694 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
695 if (dstPort == null) {
696 log.warn("Dst Port for Link {} already removed, ignoring", linkEvt);
697 return;
698 }
699
700 Link l = dstPort.getIncomingLink();
701 if ( l == null ) {
702 log.warn("Link {} already removed on destination Port", linkEvt);
703 }
704 l = srcPort.getOutgoingLink();
705 if ( l == null ) {
706 log.warn("Link {} already removed on src Port", linkEvt);
707 }
708
709 getPortImpl(dstPort).setIncomingLink(null);
710 getPortImpl(srcPort).setOutgoingLink(null);
711 }
712
713 // XXX Need to rework Device related
714 void putDevice(DeviceEvent deviceEvt) {
715 if (deviceEvt == null) {
716 throw new IllegalArgumentException("Device cannot be null");
717 }
718
719 Device device = getDeviceByMac(deviceEvt.getMac());
720 if ( device == null ) {
721 device = new DeviceImpl(this, deviceEvt.getMac());
722 Device existing = mac2Device.putIfAbsent(deviceEvt.getMac(), device);
723 if (existing != null) {
724 log.warn(
725 "Concurrent putDevice seems to be in action. Continuing updating {}",
726 existing);
727 device = existing;
728 }
729 }
730 DeviceImpl memDevice = getDeviceImpl(device);
731
732 // for each attachment point
733 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
734 // Attached Ports' Parent Switch must exist
735 Switch sw = getSwitch(swp.dpid);
736 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800737 log.warn("Switch for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800738 continue;
739 }
740 // Attached Ports must exist
741 Port port = sw.getPort(swp.number);
742 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800743 log.warn("Port for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800744 continue;
745 }
746 // Attached Ports must not have Link
747 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
748 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.", port.getOutgoingLink(), port.getIncomingLink());
749 continue;
750 }
751
752 // finally add Device <-> Port on In-memory structure
753 PortImpl memPort = getPortImpl(port);
754 memPort.addDevice(device);
755 memDevice.addAttachmentPoint(port);
756 }
757
758 // for each IP address
759 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
760 // Add Device -> IP
761 memDevice.addIpAddress(ipAddr);
762
763 // Add IP -> Set<Device>
764 boolean updated = false;
765 do {
766 Set<Device> devices = this.addr2Device.get(ipAddr);
767 if ( devices == null ) {
768 devices = new HashSet<>();
769 Set<Device> existing = this.addr2Device.putIfAbsent(ipAddr, devices);
770 if ( existing == null ) {
771 // success
772 updated = true;
773 }
774 } else {
775 Set<Device> updateDevices = new HashSet<>(devices);
776 updateDevices.add(device);
777 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
778 }
779 if (!updated) {
780 log.debug("Collision detected, updating IP to Device mapping retrying.");
781 }
782 } while( !updated );
783 }
784 }
785
786 void removeDevice(DeviceEvent deviceEvt) {
787 if (deviceEvt == null) {
788 throw new IllegalArgumentException("Device cannot be null");
789 }
790
791 Device device = getDeviceByMac(deviceEvt.getMac());
792 if ( device == null ) {
793 log.warn("Device {} already removed, ignoring", deviceEvt);
794 return;
795 }
796 DeviceImpl memDevice = getDeviceImpl(device);
797
798 // for each attachment point
799 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
800 // Attached Ports' Parent Switch must exist
801 Switch sw = getSwitch(swp.dpid);
802 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800803 log.warn("Switch for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800804 continue;
805 }
806 // Attached Ports must exist
807 Port port = sw.getPort(swp.number);
808 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800809 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800810 continue;
811 }
812
813 // finally remove Device <-> Port on In-memory structure
814 PortImpl memPort = getPortImpl(port);
815 memPort.removeDevice(device);
816 memDevice.removeAttachmentPoint(port);
817 }
818
819 // for each IP address
820 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
821 // Remove Device -> IP
822 memDevice.removeIpAddress(ipAddr);
823
824 // Remove IP -> Set<Device>
825 boolean updated = false;
826 do {
827 Set<Device> devices = this.addr2Device.get(ipAddr);
828 if ( devices == null ) {
829 // already empty set, nothing to do
830 updated = true;
831 } else {
832 Set<Device> updateDevices = new HashSet<>(devices);
833 updateDevices.remove(device);
834 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
835 }
836 if (!updated) {
837 log.debug("Collision detected, updating IP to Device mapping retrying.");
838 }
839 } while( !updated );
840 }
841 }
842
843 private SwitchImpl getSwitchImpl(Switch sw) {
844 if (sw instanceof SwitchImpl) {
845 return (SwitchImpl) sw;
846 }
847 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
848 }
849
850 private PortImpl getPortImpl(Port p) {
851 if (p instanceof PortImpl) {
852 return (PortImpl) p;
853 }
854 throw new ClassCastException("PortImpl expected, but found: " + p);
855 }
856
857 private LinkImpl getLinkImpl(Link l) {
858 if (l instanceof LinkImpl) {
859 return (LinkImpl) l;
860 }
861 throw new ClassCastException("LinkImpl expected, but found: " + l);
862 }
863
864 private DeviceImpl getDeviceImpl(Device d) {
865 if (d instanceof DeviceImpl) {
866 return (DeviceImpl) d;
867 }
868 throw new ClassCastException("DeviceImpl expected, but found: " + d);
869 }
870
871 @Deprecated
872 public void loadWholeTopologyFromDB() {
873 // XXX clear everything first?
874
875 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
876 if ( sw.getStatus() != RCSwitch.STATUS.ACTIVE ) {
877 continue;
878 }
879 putSwitchReplicationEvent(new SwitchEvent(sw.getDpid()));
880 }
881
882 for (RCPort p : RCPort.getAllPorts()) {
883 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
884 continue;
885 }
886 putPortReplicationEvent(new PortEvent(p.getDpid(), p.getNumber() ));
887 }
888
889 // TODO Is Device going to be in DB? If so, read from DB.
890 // for (RCDevice d : RCDevice.getAllDevices()) {
891 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
892 // for (byte[] portId : d.getAllPortIds() ) {
893 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
894 // }
895 // }
896
897 for (RCLink l : RCLink.getAllLinks()) {
898 putLinkReplicationEvent( new LinkEvent(l.getSrc().dpid, l.getSrc().number, l.getDst().dpid, l.getDst().number));
899 }
900 }
Jonathan Hart062a2e82014-02-03 09:41:57 -0800901}