blob: 0b836c368dfc1b2c9d25fbb113ae6b0cf6c0d28e [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) {
88 // TODO Auto-generated method stub
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080089
Jonathan Hart22eb9882014-02-11 15:52:59 -080090 }
91
92 @Override
93 public void removePortEvent(PortEvent portEvent) {
94 // TODO Auto-generated method stub
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080095
Jonathan Hart22eb9882014-02-11 15:52:59 -080096 }
97
98 @Override
99 public void putLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800100 if (prepareForAddLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800101 datastore.addLink(linkEvent);
102 putLink(linkEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800103 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -0800104 }
105 // TODO handle invariant violation
106 }
107
108 @Override
109 public void removeLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800110 if (prepareForRemoveLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800111 datastore.removeLink(linkEvent);
112 removeLink(linkEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800113 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -0800114 }
115 // TODO handle invariant violation
116 }
117
118 @Override
Yuta HIGUCHI0be4a662014-02-11 18:01:28 -0800119 public void putDeviceEvent(DeviceEvent device) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800120 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800121 // TODO Auto-generated method stub
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800122
Jonathan Hart22eb9882014-02-11 15:52:59 -0800123 }
124
125 @Override
126 public void removeDeviceEvent(DeviceEvent deviceEvent) {
127 // TODO Auto-generated method stub
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800128
Jonathan Hart22eb9882014-02-11 15:52:59 -0800129 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800130
Jonathan Hart22eb9882014-02-11 15:52:59 -0800131 /* *****************
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800132 * Internal methods to maintain invariants of the network graph
Jonathan Hart22eb9882014-02-11 15:52:59 -0800133 * *****************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800134
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800135 /**
136 *
137 * @param swEvt
138 * @return true if ready to accept event.
139 */
140 private boolean prepareForAddSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800141 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800142 // Prep: remove(deactivate) Ports on Switch, which is not on event
143 removePortsNotOnEvent(swEvt);
144 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800145 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800146
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800147 private boolean prepareForRemoveSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800148 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800149 // Prep: remove(deactivate) Ports on Switch, which is not on event
150 // XXX may be remove switch should imply wipe all ports
151 removePortsNotOnEvent(swEvt);
152 return true;
153 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800154
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800155 private void removePortsNotOnEvent(SwitchEvent swEvt) {
156 Switch sw = switches.get( swEvt.getDpid() );
157 if ( sw != null ) {
158 Set<Long> port_noOnEvent = new HashSet<>();
159 for( PortEvent portEvent : swEvt.getPorts()) {
160 port_noOnEvent.add(portEvent.getNumber());
161 }
162 // Existing ports not on event should be removed.
163 // TODO Should batch eventually for performance?
164 for( Port p : sw.getPorts() ) {
165 if ( !port_noOnEvent.contains(p.getNumber()) ) {
166 PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
167 // calling Discovery removePort() API to wipe from DB, etc.
168 removePortEvent(rmEvent);
169 }
170 }
171 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800172 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800173
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800174 private boolean prepareForAddPortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800175 // Parent Switch must exist
176 if ( getSwitch(portEvt.getDpid()) == null) {
177 return false;
178 }
179 // Prep: None
Jonathan Hart22eb9882014-02-11 15:52:59 -0800180 return true;
181 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800182
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800183 private boolean prepareForRemovePortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800184 // Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800185 Switch sw = getSwitch(portEvt.getDpid());
186 if ( sw == null ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800187 return false;
188 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800189 Port port = sw.getPort(portEvt.getNumber());
190 if ( port == null ) {
191 log.debug("Port already removed? {}", portEvt);
192 // let it pass
193 return true;
194 }
195
196 // Prep: Remove Link and Device Attachment
197 for (Device device : port.getDevices()) {
198 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
199 devEvt.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(), port.getNumber()));
200 // calling Discovery API to wipe from DB, etc.
201 removeDeviceEvent(devEvt);
202 }
203 Set<Link> links = new HashSet<>();
204 links.add(port.getOutgoingLink());
205 links.add(port.getIncomingLink());
206 for ( Link link : links) {
207 if (link == null ) {
208 continue;
209 }
210 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
211 // calling Discovery API to wipe from DB, etc.
212 removeLinkEvent(linkEvent);
213 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800214 return true;
215 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800216
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800217 private boolean prepareForAddLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800218 // Src/Dst Switch must exist
219 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
220 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
221 if ( srcSw == null || dstSw == null ) {
222 return false;
223 }
224 // Src/Dst Port must exist
225 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
226 Port dstPort = srcSw.getPort(linkEvt.getDst().number);
227 if ( srcPort == null || dstPort == null ) {
228 return false;
229 }
230
231 // Prep: remove Device attachment on both Ports
232 for (Device device : srcPort.getDevices()) {
233 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
234 devEvt.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
235 // calling Discovery API to wipe from DB, etc.
236 removeDeviceEvent(devEvt);
237 }
238 for (Device device : dstPort.getDevices()) {
239 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
240 devEvt.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(), dstPort.getNumber()));
241 // calling Discovery API to wipe from DB, etc.
242 removeDeviceEvent(devEvt);
243 }
244
245 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800246 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800247
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800248 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800249 // Src/Dst Switch must exist
250 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
251 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
252 if ( srcSw == null || dstSw == null ) {
253 return false;
254 }
255 // Src/Dst Port must exist
256 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
257 Port dstPort = srcSw.getPort(linkEvt.getDst().number);
258 if ( srcPort == null || dstPort == null ) {
259 return false;
260 }
261
262 // Prep: None
263 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800264 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800265
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800266 /**
267 *
268 * @param deviceEvt Event will be modified to remove inapplicable attachemntPoints/ipAddress
269 * @return false if this event should be dropped.
270 */
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800271 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800272 boolean preconditionBroken = false;
273 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
274 for ( PortEvent.SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800275 // Attached Ports' Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800276 Switch sw = getSwitch(swp.dpid);
277 if ( sw == null ) {
278 preconditionBroken = true;
279 failedSwitchPort.add(swp);
280 continue;
281 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800282 // Attached Ports must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800283 Port port = sw.getPort(swp.number);
284 if ( port == null ) {
285 preconditionBroken = true;
286 failedSwitchPort.add(swp);
287 continue;
288 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800289 // Attached Ports must not have Link
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800290 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
291 preconditionBroken = true;
292 failedSwitchPort.add(swp);
293 continue;
294 }
295 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800296
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800297 // Rewriting event to exclude failed attachmentPoint
298 // XXX Assumption behind this is that inapplicable device event should
299 // be dropped, not deferred. If we decide to defer Device event,
300 // rewriting can become a problem
301 List<SwitchPort> attachmentPoints = deviceEvt.getAttachmentPoints();
302 attachmentPoints.removeAll(failedSwitchPort);
303 deviceEvt.setAttachmentPoints(attachmentPoints);
304
305 if ( deviceEvt.getAttachmentPoints().isEmpty() && deviceEvt.getIpAddresses().isEmpty() ) {
306 // XXX return false to represent: Nothing left to do for this event. Caller should drop event
307 return false;
308 }
309
310 // Should we return false to tell caller that the event was trimmed?
311 // if ( preconditionBroken ) {
312 // return false;
313 // }
314
315 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800316 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800317
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800318 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800319 // No show stopping precondition?
320 // Prep: none
Jonathan Hart22eb9882014-02-11 15:52:59 -0800321 return true;
322 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800323
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800324 /* ******************************
325 * NetworkGraphReplicationInterface methods
326 * ******************************/
327
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800328 @Override
329 public void putSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800330 // TODO who is in charge of ignoring event triggered by my self?
331 // This method or caller?
332 if (prepareForAddSwitchEvent(switchEvent)) {
333 putSwitch(switchEvent);
334 }
335 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800336 }
337
338 @Override
339 public void removeSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800340 // TODO who is in charge of ignoring event triggered by my self?
341 // This method or caller?
342 if (prepareForRemoveSwitchEvent(switchEvent)) {
343 removeSwitch(switchEvent);
344 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800345 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800346 }
347
348 @Override
349 public void putPortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800350 // TODO who is in charge of ignoring event triggered by my self?
351 // This method or caller?
352 if (prepareForAddPortEvent(portEvent)) {
353 putPort(portEvent);
354 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800355 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800356 }
357
358 @Override
359 public void removePortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800360 // TODO who is in charge of ignoring event triggered by my self?
361 // This method or caller?
362 if (prepareForRemovePortEvent(portEvent)) {
363 removePort(portEvent);
364 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800365 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800366 }
367
368 @Override
369 public void putLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800370 // TODO who is in charge of ignoring event triggered by my self?
371 // This method or caller?
372 if (prepareForAddLinkEvent(linkEvent)) {
373 putLink(linkEvent);
374 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800375 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800376 }
377
378 @Override
379 public void removeLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800380 // TODO who is in charge of ignoring event triggered by my self?
381 // This method or caller?
382 if (prepareForRemoveLinkEvent(linkEvent)) {
383 removeLink(linkEvent);
384 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800385 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800386 }
387
388 @Override
389 public void putDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800390 // TODO who is in charge of ignoring event triggered by my self?
391 // This method or caller?
392 if (prepareForAddDeviceEvent(deviceEvent)) {
393 putDevice(deviceEvent);
394 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800395 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800396 }
397
398 @Override
399 public void removeDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800400 // TODO who is in charge of ignoring event triggered by my self?
401 // This method or caller?
402 if (prepareForRemoveDeviceEvent(deviceEvent)) {
403 removeDevice(deviceEvent);
404 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800405 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800406 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800407
408 /* ************************************************
409 * Internal In-memory object mutation methods.
410 * ************************************************/
411
412 void putSwitch(SwitchEvent swEvt) {
413 if (swEvt == null) {
414 throw new IllegalArgumentException("Switch cannot be null");
415 }
416
417 Switch sw = switches.get(swEvt.getDpid());
418
419 if (sw == null) {
420 sw = new SwitchImpl(this, swEvt.getDpid());
421 Switch existing = switches.putIfAbsent(swEvt.getDpid(), sw);
422 if (existing != null) {
423 log.warn(
424 "Concurrent putSwitch not expected. Continuing updating {}",
425 existing);
426 sw = existing;
427 }
428 }
429
430 // Update when more attributes are added to Event object
431 // no attribute to update for now
432
433 // TODO handle child Port event properly for performance
434 for (PortEvent portEvt : swEvt.getPorts() ) {
435 putPort(portEvt);
436 }
437
438 }
439
440 void removeSwitch(SwitchEvent swEvt) {
441 if (swEvt == null) {
442 throw new IllegalArgumentException("Switch cannot be null");
443 }
444
445 // TODO handle child Port event properly for performance
446 for (PortEvent portEvt : swEvt.getPorts() ) {
447 removePort(portEvt);
448 }
449
450 Switch sw = switches.get(swEvt.getDpid());
451
452 if (sw == null) {
453 log.warn("Switch {} already removed, ignoring", swEvt);
454 return;
455 }
456
457 // Sanity check
458 if (!sw.getPorts().isEmpty()) {
459 log.warn(
460 "Ports on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
461 swEvt);
462 // XXX Should we remove Port?
463 }
464 if (!sw.getDevices().isEmpty()) {
465 log.warn(
466 "Devices on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
467 swEvt);
468 // XXX Should we remove Device to Switch relation?
469 }
470 if (!sw.getIncomingLinks().iterator().hasNext()) {
471 log.warn(
472 "IncomingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
473 swEvt);
474 // XXX Should we remove Link?
475 }
476 if (!sw.getOutgoingLinks().iterator().hasNext()) {
477 log.warn(
478 "OutgoingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
479 swEvt);
480 // XXX Should we remove Link?
481 }
482
483 boolean removed = switches.remove(swEvt.getDpid(), sw);
484 if (removed) {
485 log.warn(
486 "Switch instance was replaced concurrently while removing {}. Something is not right.",
487 sw);
488 }
489 }
490
491 void putPort(PortEvent portEvt) {
492 if (portEvt == null) {
493 throw new IllegalArgumentException("Port cannot be null");
494 }
495 Switch sw = switches.get(portEvt.getDpid());
496 if (sw == null) {
497 throw new BrokenInvariantException(String.format(
498 "Switch with dpid %s did not exist.",
499 new Dpid(portEvt.getDpid())));
500 }
501 Port p = sw.getPort(portEvt.getNumber());
502 PortImpl port = null;
503 if (p != null) {
504 port = getPortImpl(p);
505 }
506
507 if (port == null) {
508 port = new PortImpl(this, sw, portEvt.getNumber());
509 }
510
511 // TODO update attributes
512
513 SwitchImpl s = getSwitchImpl(sw);
514 s.addPort(port);
515 }
516
517 void removePort(PortEvent portEvt) {
518 if (portEvt == null) {
519 throw new IllegalArgumentException("Port cannot be null");
520 }
521
522 Switch sw = switches.get(portEvt.getDpid());
523 if (sw == null) {
524 log.warn("Parent Switch for Port {} already removed, ignoring", portEvt);
525 return;
526 }
527
528 Port p = sw.getPort(portEvt.getNumber());
529 if (p == null) {
530 log.warn("Port {} already removed, ignoring", portEvt);
531 return;
532 }
533
534 // check if there is something referring to this Port
535
536 if (!p.getDevices().iterator().hasNext()) {
537 log.warn(
538 "Devices on Port {} should be removed prior to removing Port. Removing Port anyways",
539 portEvt);
540 // XXX Should we remove Device to Port relation?
541 }
542 if (p.getIncomingLink() != null) {
543 log.warn(
544 "IncomingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
545 portEvt);
546 // XXX Should we remove Link?
547 }
548 if (p.getOutgoingLink() != null) {
549 log.warn(
550 "OutgoingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
551 portEvt);
552 // XXX Should we remove Link?
553 }
554
555 // remove Port from Switch
556 SwitchImpl s = getSwitchImpl(sw);
557 s.removePort(p);
558 }
559
560 void putLink(LinkEvent linkEvt) {
561 if (linkEvt == null) {
562 throw new IllegalArgumentException("Link cannot be null");
563 }
564
565 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
566 if (srcSw == null) {
567 throw new BrokenInvariantException(
568 String.format(
569 "Switch with dpid %s did not exist.",
570 new Dpid(linkEvt.getSrc().dpid)));
571 }
572
573 Switch dstSw = switches.get(linkEvt.getDst().dpid);
574 if (dstSw == null) {
575 throw new BrokenInvariantException(
576 String.format(
577 "Switch with dpid %s did not exist.",
578 new Dpid(linkEvt.getDst().dpid)));
579 }
580
581 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
582 if (srcPort == null) {
583 throw new BrokenInvariantException(
584 String.format(
585 "Src Port %s of a Link did not exist.",
586 linkEvt.getSrc() ));
587 }
588
589 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
590 if (dstPort == null) {
591 throw new BrokenInvariantException(
592 String.format(
593 "Dst Port %s of a Link did not exist.",
594 linkEvt.getDst() ));
595 }
596
597 // getting Link instance from destination port incoming Link
598 Link l = dstPort.getIncomingLink();
599 LinkImpl link = null;
600 assert( l == srcPort.getOutgoingLink() );
601 if (l != null) {
602 link = getLinkImpl(l);
603 }
604
605 if (link == null) {
606 link = new LinkImpl(this, srcPort, dstPort);
607 }
608
609
610 PortImpl dstPortMem = getPortImpl(dstPort);
611 PortImpl srcPortMem = getPortImpl(srcPort);
612
613 // Add Link first to avoid further Device addition
614
615 // add Link to Port
616 dstPortMem.setIncomingLink(link);
617 srcPortMem.setOutgoingLink(link);
618
619 // remove Device Pointing to Port if any
620 for(Device d : dstPortMem.getDevices() ) {
621 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, dstPort, linkEvt);
622 DeviceImpl dev = getDeviceImpl(d);
623 dev.removeAttachmentPoint(dstPort);
624 // XXX This implies that change is made to Device Object,
625 // which need to be written to DB, how should that be done?
626 // should we write here or ignore and leave DB in inconsistent state?
627 }
628 dstPortMem.removeAllDevice();
629 for(Device d : srcPortMem.getDevices() ) {
630 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, srcPort, linkEvt);
631 DeviceImpl dev = getDeviceImpl(d);
632 dev.removeAttachmentPoint(srcPort);
633 // XXX This implies that change is made to Device Object,
634 // which need to be written to DB, how should that be done?
635 // should we write here or ignore and leave DB in inconsistent state?
636 }
637 srcPortMem.removeAllDevice();
638
639 }
640
641 void removeLink(LinkEvent linkEvt) {
642 if (linkEvt == null) {
643 throw new IllegalArgumentException("Link cannot be null");
644 }
645
646 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
647 if (srcSw == null) {
648 log.warn("Src Switch for Link {} already removed, ignoring", linkEvt);
649 return;
650 }
651
652 Switch dstSw = switches.get(linkEvt.getDst().dpid);
653 if (dstSw == null) {
654 log.warn("Dst Switch for Link {} already removed, ignoring", linkEvt);
655 return;
656 }
657
658 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
659 if (srcPort == null) {
660 log.warn("Src Port for Link {} already removed, ignoring", linkEvt);
661 return;
662 }
663
664 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
665 if (dstPort == null) {
666 log.warn("Dst Port for Link {} already removed, ignoring", linkEvt);
667 return;
668 }
669
670 Link l = dstPort.getIncomingLink();
671 if ( l == null ) {
672 log.warn("Link {} already removed on destination Port", linkEvt);
673 }
674 l = srcPort.getOutgoingLink();
675 if ( l == null ) {
676 log.warn("Link {} already removed on src Port", linkEvt);
677 }
678
679 getPortImpl(dstPort).setIncomingLink(null);
680 getPortImpl(srcPort).setOutgoingLink(null);
681 }
682
683 // XXX Need to rework Device related
684 void putDevice(DeviceEvent deviceEvt) {
685 if (deviceEvt == null) {
686 throw new IllegalArgumentException("Device cannot be null");
687 }
688
689 Device device = getDeviceByMac(deviceEvt.getMac());
690 if ( device == null ) {
691 device = new DeviceImpl(this, deviceEvt.getMac());
692 Device existing = mac2Device.putIfAbsent(deviceEvt.getMac(), device);
693 if (existing != null) {
694 log.warn(
695 "Concurrent putDevice seems to be in action. Continuing updating {}",
696 existing);
697 device = existing;
698 }
699 }
700 DeviceImpl memDevice = getDeviceImpl(device);
701
702 // for each attachment point
703 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
704 // Attached Ports' Parent Switch must exist
705 Switch sw = getSwitch(swp.dpid);
706 if ( sw == null ) {
707 log.warn("Switch {} for the attachment point did not exist. skipping mutation", sw);
708 continue;
709 }
710 // Attached Ports must exist
711 Port port = sw.getPort(swp.number);
712 if ( port == null ) {
713 log.warn("Port {} for the attachment point did not exist. skipping mutation", port);
714 continue;
715 }
716 // Attached Ports must not have Link
717 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
718 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.", port.getOutgoingLink(), port.getIncomingLink());
719 continue;
720 }
721
722 // finally add Device <-> Port on In-memory structure
723 PortImpl memPort = getPortImpl(port);
724 memPort.addDevice(device);
725 memDevice.addAttachmentPoint(port);
726 }
727
728 // for each IP address
729 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
730 // Add Device -> IP
731 memDevice.addIpAddress(ipAddr);
732
733 // Add IP -> Set<Device>
734 boolean updated = false;
735 do {
736 Set<Device> devices = this.addr2Device.get(ipAddr);
737 if ( devices == null ) {
738 devices = new HashSet<>();
739 Set<Device> existing = this.addr2Device.putIfAbsent(ipAddr, devices);
740 if ( existing == null ) {
741 // success
742 updated = true;
743 }
744 } else {
745 Set<Device> updateDevices = new HashSet<>(devices);
746 updateDevices.add(device);
747 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
748 }
749 if (!updated) {
750 log.debug("Collision detected, updating IP to Device mapping retrying.");
751 }
752 } while( !updated );
753 }
754 }
755
756 void removeDevice(DeviceEvent deviceEvt) {
757 if (deviceEvt == null) {
758 throw new IllegalArgumentException("Device cannot be null");
759 }
760
761 Device device = getDeviceByMac(deviceEvt.getMac());
762 if ( device == null ) {
763 log.warn("Device {} already removed, ignoring", deviceEvt);
764 return;
765 }
766 DeviceImpl memDevice = getDeviceImpl(device);
767
768 // for each attachment point
769 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
770 // Attached Ports' Parent Switch must exist
771 Switch sw = getSwitch(swp.dpid);
772 if ( sw == null ) {
773 log.warn("Switch {} for the attachment point did not exist. skipping attachment point mutation", sw);
774 continue;
775 }
776 // Attached Ports must exist
777 Port port = sw.getPort(swp.number);
778 if ( port == null ) {
779 log.warn("Port {} for the attachment point did not exist. skipping attachment point mutation", port);
780 continue;
781 }
782
783 // finally remove Device <-> Port on In-memory structure
784 PortImpl memPort = getPortImpl(port);
785 memPort.removeDevice(device);
786 memDevice.removeAttachmentPoint(port);
787 }
788
789 // for each IP address
790 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
791 // Remove Device -> IP
792 memDevice.removeIpAddress(ipAddr);
793
794 // Remove IP -> Set<Device>
795 boolean updated = false;
796 do {
797 Set<Device> devices = this.addr2Device.get(ipAddr);
798 if ( devices == null ) {
799 // already empty set, nothing to do
800 updated = true;
801 } else {
802 Set<Device> updateDevices = new HashSet<>(devices);
803 updateDevices.remove(device);
804 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
805 }
806 if (!updated) {
807 log.debug("Collision detected, updating IP to Device mapping retrying.");
808 }
809 } while( !updated );
810 }
811 }
812
813 private SwitchImpl getSwitchImpl(Switch sw) {
814 if (sw instanceof SwitchImpl) {
815 return (SwitchImpl) sw;
816 }
817 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
818 }
819
820 private PortImpl getPortImpl(Port p) {
821 if (p instanceof PortImpl) {
822 return (PortImpl) p;
823 }
824 throw new ClassCastException("PortImpl expected, but found: " + p);
825 }
826
827 private LinkImpl getLinkImpl(Link l) {
828 if (l instanceof LinkImpl) {
829 return (LinkImpl) l;
830 }
831 throw new ClassCastException("LinkImpl expected, but found: " + l);
832 }
833
834 private DeviceImpl getDeviceImpl(Device d) {
835 if (d instanceof DeviceImpl) {
836 return (DeviceImpl) d;
837 }
838 throw new ClassCastException("DeviceImpl expected, but found: " + d);
839 }
840
841 @Deprecated
842 public void loadWholeTopologyFromDB() {
843 // XXX clear everything first?
844
845 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
846 if ( sw.getStatus() != RCSwitch.STATUS.ACTIVE ) {
847 continue;
848 }
849 putSwitchReplicationEvent(new SwitchEvent(sw.getDpid()));
850 }
851
852 for (RCPort p : RCPort.getAllPorts()) {
853 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
854 continue;
855 }
856 putPortReplicationEvent(new PortEvent(p.getDpid(), p.getNumber() ));
857 }
858
859 // TODO Is Device going to be in DB? If so, read from DB.
860 // for (RCDevice d : RCDevice.getAllDevices()) {
861 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
862 // for (byte[] portId : d.getAllPortIds() ) {
863 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
864 // }
865 // }
866
867 for (RCLink l : RCLink.getAllLinks()) {
868 putLinkReplicationEvent( new LinkEvent(l.getSrc().dpid, l.getSrc().number, l.getDst().dpid, l.getDst().number));
869 }
870 }
Jonathan Hart062a2e82014-02-03 09:41:57 -0800871}