blob: 0db9ef922cd57f84a14a4b090f4e8b134152f2fc [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?
179 for( Port p : sw.getPorts() ) {
180 if ( !port_noOnEvent.contains(p.getNumber()) ) {
181 PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
182 // calling Discovery removePort() API to wipe from DB, etc.
183 removePortEvent(rmEvent);
184 }
185 }
186 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800187 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800188
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800189 private boolean prepareForAddPortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800190 // Parent Switch must exist
191 if ( getSwitch(portEvt.getDpid()) == null) {
192 return false;
193 }
194 // Prep: None
Jonathan Hart22eb9882014-02-11 15:52:59 -0800195 return true;
196 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800197
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800198 private boolean prepareForRemovePortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800199 // Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800200 Switch sw = getSwitch(portEvt.getDpid());
201 if ( sw == null ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800202 return false;
203 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800204 Port port = sw.getPort(portEvt.getNumber());
205 if ( port == null ) {
206 log.debug("Port already removed? {}", portEvt);
207 // let it pass
208 return true;
209 }
210
211 // Prep: Remove Link and Device Attachment
212 for (Device device : port.getDevices()) {
213 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
214 devEvt.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(), port.getNumber()));
215 // calling Discovery API to wipe from DB, etc.
216 removeDeviceEvent(devEvt);
217 }
218 Set<Link> links = new HashSet<>();
219 links.add(port.getOutgoingLink());
220 links.add(port.getIncomingLink());
221 for ( Link link : links) {
222 if (link == null ) {
223 continue;
224 }
225 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
226 // calling Discovery API to wipe from DB, etc.
227 removeLinkEvent(linkEvent);
228 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800229 return true;
230 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800231
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800232 private boolean prepareForAddLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800233 // Src/Dst Switch must exist
234 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
235 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
236 if ( srcSw == null || dstSw == null ) {
237 return false;
238 }
239 // Src/Dst Port must exist
240 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Jonathan Hart4c263272014-02-13 17:41:05 -0800241 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800242 if ( srcPort == null || dstPort == null ) {
243 return false;
244 }
245
246 // Prep: remove Device attachment on both Ports
247 for (Device device : srcPort.getDevices()) {
248 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
249 devEvt.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
250 // calling Discovery API to wipe from DB, etc.
251 removeDeviceEvent(devEvt);
252 }
253 for (Device device : dstPort.getDevices()) {
254 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
255 devEvt.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(), dstPort.getNumber()));
256 // calling Discovery API to wipe from DB, etc.
257 removeDeviceEvent(devEvt);
258 }
259
260 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800261 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800262
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800263 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800264 // Src/Dst Switch must exist
265 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
266 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
267 if ( srcSw == null || dstSw == null ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800268 log.warn("Rejecting removeLink {} because switch doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800269 return false;
270 }
271 // Src/Dst Port must exist
272 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800273 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800274 if ( srcPort == null || dstPort == null ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800275 log.warn("Rejecting removeLink {} because port doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800276 return false;
277 }
278
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800279 Link link = srcPort.getOutgoingLink();
280
281 // Link is already gone, or different Link exist in memory
282 // XXX Check if we should reject or just accept these cases.
283 // it should be harmless to remove the Link on event from DB anyways
284 if (link == null ||
285 !link.getDestinationPortNumber().equals(linkEvt.getDst().number)
286 || !link.getDestinationSwitchDpid().equals(linkEvt.getDst().dpid)) {
287 log.warn("Rejecting removeLink {} because link doesn't exist", linkEvt);
288 return false;
289 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800290 // Prep: None
291 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800292 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800293
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800294 /**
295 *
296 * @param deviceEvt Event will be modified to remove inapplicable attachemntPoints/ipAddress
297 * @return false if this event should be dropped.
298 */
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800299 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800300 boolean preconditionBroken = false;
301 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
302 for ( PortEvent.SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800303 // Attached Ports' Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800304 Switch sw = getSwitch(swp.dpid);
305 if ( sw == null ) {
306 preconditionBroken = true;
307 failedSwitchPort.add(swp);
308 continue;
309 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800310 // Attached Ports must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800311 Port port = sw.getPort(swp.number);
312 if ( port == null ) {
313 preconditionBroken = true;
314 failedSwitchPort.add(swp);
315 continue;
316 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800317 // Attached Ports must not have Link
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800318 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
319 preconditionBroken = true;
320 failedSwitchPort.add(swp);
321 continue;
322 }
323 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800324
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800325 // Rewriting event to exclude failed attachmentPoint
326 // XXX Assumption behind this is that inapplicable device event should
327 // be dropped, not deferred. If we decide to defer Device event,
328 // rewriting can become a problem
329 List<SwitchPort> attachmentPoints = deviceEvt.getAttachmentPoints();
330 attachmentPoints.removeAll(failedSwitchPort);
331 deviceEvt.setAttachmentPoints(attachmentPoints);
332
333 if ( deviceEvt.getAttachmentPoints().isEmpty() && deviceEvt.getIpAddresses().isEmpty() ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800334 // return false to represent: Nothing left to do for this event. Caller should drop event
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800335 return false;
336 }
337
338 // Should we return false to tell caller that the event was trimmed?
339 // if ( preconditionBroken ) {
340 // return false;
341 // }
342
343 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800344 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800345
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800346 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800347 // No show stopping precondition?
348 // Prep: none
Jonathan Hart22eb9882014-02-11 15:52:59 -0800349 return true;
350 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800351
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800352 /* ******************************
353 * NetworkGraphReplicationInterface methods
354 * ******************************/
355
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800356 @Override
357 public void putSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800358 if (prepareForAddSwitchEvent(switchEvent)) {
359 putSwitch(switchEvent);
360 }
361 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800362 }
363
364 @Override
365 public void removeSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800366 if (prepareForRemoveSwitchEvent(switchEvent)) {
367 removeSwitch(switchEvent);
368 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800369 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800370 }
371
372 @Override
373 public void putPortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800374 if (prepareForAddPortEvent(portEvent)) {
375 putPort(portEvent);
376 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800377 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800378 }
379
380 @Override
381 public void removePortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800382 if (prepareForRemovePortEvent(portEvent)) {
383 removePort(portEvent);
384 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800385 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800386 }
387
388 @Override
389 public void putLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800390 if (prepareForAddLinkEvent(linkEvent)) {
391 putLink(linkEvent);
392 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800393 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800394 }
395
396 @Override
397 public void removeLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800398 if (prepareForRemoveLinkEvent(linkEvent)) {
399 removeLink(linkEvent);
400 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800401 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800402 }
403
404 @Override
405 public void putDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800406 if (prepareForAddDeviceEvent(deviceEvent)) {
407 putDevice(deviceEvent);
408 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800409 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800410 }
411
412 @Override
413 public void removeDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800414 if (prepareForRemoveDeviceEvent(deviceEvent)) {
415 removeDevice(deviceEvent);
416 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800417 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800418 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800419
420 /* ************************************************
421 * Internal In-memory object mutation methods.
422 * ************************************************/
423
424 void putSwitch(SwitchEvent swEvt) {
425 if (swEvt == null) {
426 throw new IllegalArgumentException("Switch cannot be null");
427 }
428
429 Switch sw = switches.get(swEvt.getDpid());
430
431 if (sw == null) {
432 sw = new SwitchImpl(this, swEvt.getDpid());
433 Switch existing = switches.putIfAbsent(swEvt.getDpid(), sw);
434 if (existing != null) {
435 log.warn(
436 "Concurrent putSwitch not expected. Continuing updating {}",
437 existing);
438 sw = existing;
439 }
440 }
441
442 // Update when more attributes are added to Event object
443 // no attribute to update for now
444
445 // TODO handle child Port event properly for performance
446 for (PortEvent portEvt : swEvt.getPorts() ) {
447 putPort(portEvt);
448 }
449
450 }
451
452 void removeSwitch(SwitchEvent swEvt) {
453 if (swEvt == null) {
454 throw new IllegalArgumentException("Switch cannot be null");
455 }
456
457 // TODO handle child Port event properly for performance
458 for (PortEvent portEvt : swEvt.getPorts() ) {
459 removePort(portEvt);
460 }
461
462 Switch sw = switches.get(swEvt.getDpid());
463
464 if (sw == null) {
465 log.warn("Switch {} already removed, ignoring", swEvt);
466 return;
467 }
468
469 // Sanity check
470 if (!sw.getPorts().isEmpty()) {
471 log.warn(
472 "Ports on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
473 swEvt);
474 // XXX Should we remove Port?
475 }
476 if (!sw.getDevices().isEmpty()) {
477 log.warn(
478 "Devices on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
479 swEvt);
480 // XXX Should we remove Device to Switch relation?
481 }
482 if (!sw.getIncomingLinks().iterator().hasNext()) {
483 log.warn(
484 "IncomingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
485 swEvt);
486 // XXX Should we remove Link?
487 }
488 if (!sw.getOutgoingLinks().iterator().hasNext()) {
489 log.warn(
490 "OutgoingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
491 swEvt);
492 // XXX Should we remove Link?
493 }
494
495 boolean removed = switches.remove(swEvt.getDpid(), sw);
496 if (removed) {
497 log.warn(
498 "Switch instance was replaced concurrently while removing {}. Something is not right.",
499 sw);
500 }
501 }
502
503 void putPort(PortEvent portEvt) {
504 if (portEvt == null) {
505 throw new IllegalArgumentException("Port cannot be null");
506 }
507 Switch sw = switches.get(portEvt.getDpid());
508 if (sw == null) {
509 throw new BrokenInvariantException(String.format(
510 "Switch with dpid %s did not exist.",
511 new Dpid(portEvt.getDpid())));
512 }
513 Port p = sw.getPort(portEvt.getNumber());
514 PortImpl port = null;
515 if (p != null) {
516 port = getPortImpl(p);
517 }
518
519 if (port == null) {
520 port = new PortImpl(this, sw, portEvt.getNumber());
521 }
522
523 // TODO update attributes
524
525 SwitchImpl s = getSwitchImpl(sw);
526 s.addPort(port);
527 }
528
529 void removePort(PortEvent portEvt) {
530 if (portEvt == null) {
531 throw new IllegalArgumentException("Port cannot be null");
532 }
533
534 Switch sw = switches.get(portEvt.getDpid());
535 if (sw == null) {
536 log.warn("Parent Switch for Port {} already removed, ignoring", portEvt);
537 return;
538 }
539
540 Port p = sw.getPort(portEvt.getNumber());
541 if (p == null) {
542 log.warn("Port {} already removed, ignoring", portEvt);
543 return;
544 }
545
546 // check if there is something referring to this Port
547
548 if (!p.getDevices().iterator().hasNext()) {
549 log.warn(
550 "Devices on Port {} should be removed prior to removing Port. Removing Port anyways",
551 portEvt);
552 // XXX Should we remove Device to Port relation?
553 }
554 if (p.getIncomingLink() != null) {
555 log.warn(
556 "IncomingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
557 portEvt);
558 // XXX Should we remove Link?
559 }
560 if (p.getOutgoingLink() != null) {
561 log.warn(
562 "OutgoingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
563 portEvt);
564 // XXX Should we remove Link?
565 }
566
567 // remove Port from Switch
568 SwitchImpl s = getSwitchImpl(sw);
569 s.removePort(p);
570 }
571
572 void putLink(LinkEvent linkEvt) {
573 if (linkEvt == null) {
574 throw new IllegalArgumentException("Link cannot be null");
575 }
576
577 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
578 if (srcSw == null) {
579 throw new BrokenInvariantException(
580 String.format(
581 "Switch with dpid %s did not exist.",
582 new Dpid(linkEvt.getSrc().dpid)));
583 }
584
585 Switch dstSw = switches.get(linkEvt.getDst().dpid);
586 if (dstSw == null) {
587 throw new BrokenInvariantException(
588 String.format(
589 "Switch with dpid %s did not exist.",
590 new Dpid(linkEvt.getDst().dpid)));
591 }
592
593 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
594 if (srcPort == null) {
595 throw new BrokenInvariantException(
596 String.format(
597 "Src Port %s of a Link did not exist.",
598 linkEvt.getSrc() ));
599 }
600
601 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
602 if (dstPort == null) {
603 throw new BrokenInvariantException(
604 String.format(
605 "Dst Port %s of a Link did not exist.",
606 linkEvt.getDst() ));
607 }
608
609 // getting Link instance from destination port incoming Link
610 Link l = dstPort.getIncomingLink();
611 LinkImpl link = null;
612 assert( l == srcPort.getOutgoingLink() );
613 if (l != null) {
614 link = getLinkImpl(l);
615 }
616
617 if (link == null) {
618 link = new LinkImpl(this, srcPort, dstPort);
619 }
620
621
622 PortImpl dstPortMem = getPortImpl(dstPort);
623 PortImpl srcPortMem = getPortImpl(srcPort);
624
625 // Add Link first to avoid further Device addition
626
627 // add Link to Port
628 dstPortMem.setIncomingLink(link);
629 srcPortMem.setOutgoingLink(link);
630
631 // remove Device Pointing to Port if any
632 for(Device d : dstPortMem.getDevices() ) {
633 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, dstPort, linkEvt);
634 DeviceImpl dev = getDeviceImpl(d);
635 dev.removeAttachmentPoint(dstPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800636 // This implies that change is made to Device Object.
637 // sending Device attachment point removed event
638 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
639 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
640 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800641 }
642 dstPortMem.removeAllDevice();
643 for(Device d : srcPortMem.getDevices() ) {
644 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, srcPort, linkEvt);
645 DeviceImpl dev = getDeviceImpl(d);
646 dev.removeAttachmentPoint(srcPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800647 // This implies that change is made to Device Object.
648 // sending Device attachment point removed event
649 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
650 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
651 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800652 }
653 srcPortMem.removeAllDevice();
654
655 }
656
657 void removeLink(LinkEvent linkEvt) {
658 if (linkEvt == null) {
659 throw new IllegalArgumentException("Link cannot be null");
660 }
661
662 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
663 if (srcSw == null) {
664 log.warn("Src Switch for Link {} already removed, ignoring", linkEvt);
665 return;
666 }
667
668 Switch dstSw = switches.get(linkEvt.getDst().dpid);
669 if (dstSw == null) {
670 log.warn("Dst Switch for Link {} already removed, ignoring", linkEvt);
671 return;
672 }
673
674 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
675 if (srcPort == null) {
676 log.warn("Src Port for Link {} already removed, ignoring", linkEvt);
677 return;
678 }
679
680 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
681 if (dstPort == null) {
682 log.warn("Dst Port for Link {} already removed, ignoring", linkEvt);
683 return;
684 }
685
686 Link l = dstPort.getIncomingLink();
687 if ( l == null ) {
688 log.warn("Link {} already removed on destination Port", linkEvt);
689 }
690 l = srcPort.getOutgoingLink();
691 if ( l == null ) {
692 log.warn("Link {} already removed on src Port", linkEvt);
693 }
694
695 getPortImpl(dstPort).setIncomingLink(null);
696 getPortImpl(srcPort).setOutgoingLink(null);
697 }
698
699 // XXX Need to rework Device related
700 void putDevice(DeviceEvent deviceEvt) {
701 if (deviceEvt == null) {
702 throw new IllegalArgumentException("Device cannot be null");
703 }
704
705 Device device = getDeviceByMac(deviceEvt.getMac());
706 if ( device == null ) {
707 device = new DeviceImpl(this, deviceEvt.getMac());
708 Device existing = mac2Device.putIfAbsent(deviceEvt.getMac(), device);
709 if (existing != null) {
710 log.warn(
711 "Concurrent putDevice seems to be in action. Continuing updating {}",
712 existing);
713 device = existing;
714 }
715 }
716 DeviceImpl memDevice = getDeviceImpl(device);
717
718 // for each attachment point
719 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
720 // Attached Ports' Parent Switch must exist
721 Switch sw = getSwitch(swp.dpid);
722 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800723 log.warn("Switch for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800724 continue;
725 }
726 // Attached Ports must exist
727 Port port = sw.getPort(swp.number);
728 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800729 log.warn("Port for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800730 continue;
731 }
732 // Attached Ports must not have Link
733 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
734 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.", port.getOutgoingLink(), port.getIncomingLink());
735 continue;
736 }
737
738 // finally add Device <-> Port on In-memory structure
739 PortImpl memPort = getPortImpl(port);
740 memPort.addDevice(device);
741 memDevice.addAttachmentPoint(port);
742 }
743
744 // for each IP address
745 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
746 // Add Device -> IP
747 memDevice.addIpAddress(ipAddr);
748
749 // Add IP -> Set<Device>
750 boolean updated = false;
751 do {
752 Set<Device> devices = this.addr2Device.get(ipAddr);
753 if ( devices == null ) {
754 devices = new HashSet<>();
755 Set<Device> existing = this.addr2Device.putIfAbsent(ipAddr, devices);
756 if ( existing == null ) {
757 // success
758 updated = true;
759 }
760 } else {
761 Set<Device> updateDevices = new HashSet<>(devices);
762 updateDevices.add(device);
763 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
764 }
765 if (!updated) {
766 log.debug("Collision detected, updating IP to Device mapping retrying.");
767 }
768 } while( !updated );
769 }
770 }
771
772 void removeDevice(DeviceEvent deviceEvt) {
773 if (deviceEvt == null) {
774 throw new IllegalArgumentException("Device cannot be null");
775 }
776
777 Device device = getDeviceByMac(deviceEvt.getMac());
778 if ( device == null ) {
779 log.warn("Device {} already removed, ignoring", deviceEvt);
780 return;
781 }
782 DeviceImpl memDevice = getDeviceImpl(device);
783
784 // for each attachment point
785 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
786 // Attached Ports' Parent Switch must exist
787 Switch sw = getSwitch(swp.dpid);
788 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800789 log.warn("Switch for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800790 continue;
791 }
792 // Attached Ports must exist
793 Port port = sw.getPort(swp.number);
794 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800795 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800796 continue;
797 }
798
799 // finally remove Device <-> Port on In-memory structure
800 PortImpl memPort = getPortImpl(port);
801 memPort.removeDevice(device);
802 memDevice.removeAttachmentPoint(port);
803 }
804
805 // for each IP address
806 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
807 // Remove Device -> IP
808 memDevice.removeIpAddress(ipAddr);
809
810 // Remove IP -> Set<Device>
811 boolean updated = false;
812 do {
813 Set<Device> devices = this.addr2Device.get(ipAddr);
814 if ( devices == null ) {
815 // already empty set, nothing to do
816 updated = true;
817 } else {
818 Set<Device> updateDevices = new HashSet<>(devices);
819 updateDevices.remove(device);
820 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
821 }
822 if (!updated) {
823 log.debug("Collision detected, updating IP to Device mapping retrying.");
824 }
825 } while( !updated );
826 }
827 }
828
829 private SwitchImpl getSwitchImpl(Switch sw) {
830 if (sw instanceof SwitchImpl) {
831 return (SwitchImpl) sw;
832 }
833 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
834 }
835
836 private PortImpl getPortImpl(Port p) {
837 if (p instanceof PortImpl) {
838 return (PortImpl) p;
839 }
840 throw new ClassCastException("PortImpl expected, but found: " + p);
841 }
842
843 private LinkImpl getLinkImpl(Link l) {
844 if (l instanceof LinkImpl) {
845 return (LinkImpl) l;
846 }
847 throw new ClassCastException("LinkImpl expected, but found: " + l);
848 }
849
850 private DeviceImpl getDeviceImpl(Device d) {
851 if (d instanceof DeviceImpl) {
852 return (DeviceImpl) d;
853 }
854 throw new ClassCastException("DeviceImpl expected, but found: " + d);
855 }
856
857 @Deprecated
858 public void loadWholeTopologyFromDB() {
859 // XXX clear everything first?
860
861 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
862 if ( sw.getStatus() != RCSwitch.STATUS.ACTIVE ) {
863 continue;
864 }
865 putSwitchReplicationEvent(new SwitchEvent(sw.getDpid()));
866 }
867
868 for (RCPort p : RCPort.getAllPorts()) {
869 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
870 continue;
871 }
872 putPortReplicationEvent(new PortEvent(p.getDpid(), p.getNumber() ));
873 }
874
875 // TODO Is Device going to be in DB? If so, read from DB.
876 // for (RCDevice d : RCDevice.getAllDevices()) {
877 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
878 // for (byte[] portId : d.getAllPortIds() ) {
879 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
880 // }
881 // }
882
883 for (RCLink l : RCLink.getAllLinks()) {
884 putLinkReplicationEvent( new LinkEvent(l.getSrc().dpid, l.getSrc().number, l.getDst().dpid, l.getDst().number));
885 }
886 }
Jonathan Hart062a2e82014-02-03 09:41:57 -0800887}