blob: 9dd3877958aae01a67e491f0994cbdbbf56e9b3b [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 HIGUCHI0be4a662014-02-11 18:01:28 -0800127 public void putDeviceEvent(DeviceEvent device) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800128 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800129 // TODO Auto-generated method stub
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800130
Jonathan Hart22eb9882014-02-11 15:52:59 -0800131 }
132
133 @Override
134 public void removeDeviceEvent(DeviceEvent deviceEvent) {
135 // TODO Auto-generated method stub
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800136
Jonathan Hart22eb9882014-02-11 15:52:59 -0800137 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800138
Jonathan Hart22eb9882014-02-11 15:52:59 -0800139 /* *****************
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800140 * Internal methods to maintain invariants of the network graph
Jonathan Hart22eb9882014-02-11 15:52:59 -0800141 * *****************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800142
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800143 /**
144 *
145 * @param swEvt
146 * @return true if ready to accept event.
147 */
148 private boolean prepareForAddSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800149 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800150 // Prep: remove(deactivate) Ports on Switch, which is not on event
151 removePortsNotOnEvent(swEvt);
152 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800153 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800154
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800155 private boolean prepareForRemoveSwitchEvent(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 // XXX may be remove switch should imply wipe all ports
159 removePortsNotOnEvent(swEvt);
160 return true;
161 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800162
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800163 private void removePortsNotOnEvent(SwitchEvent swEvt) {
164 Switch sw = switches.get( swEvt.getDpid() );
165 if ( sw != null ) {
166 Set<Long> port_noOnEvent = new HashSet<>();
167 for( PortEvent portEvent : swEvt.getPorts()) {
168 port_noOnEvent.add(portEvent.getNumber());
169 }
170 // Existing ports not on event should be removed.
171 // TODO Should batch eventually for performance?
172 for( Port p : sw.getPorts() ) {
173 if ( !port_noOnEvent.contains(p.getNumber()) ) {
174 PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
175 // calling Discovery removePort() API to wipe from DB, etc.
176 removePortEvent(rmEvent);
177 }
178 }
179 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800180 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800181
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800182 private boolean prepareForAddPortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800183 // Parent Switch must exist
184 if ( getSwitch(portEvt.getDpid()) == null) {
185 return false;
186 }
187 // Prep: None
Jonathan Hart22eb9882014-02-11 15:52:59 -0800188 return true;
189 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800190
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800191 private boolean prepareForRemovePortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800192 // Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800193 Switch sw = getSwitch(portEvt.getDpid());
194 if ( sw == null ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800195 return false;
196 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800197 Port port = sw.getPort(portEvt.getNumber());
198 if ( port == null ) {
199 log.debug("Port already removed? {}", portEvt);
200 // let it pass
201 return true;
202 }
203
204 // Prep: Remove Link and Device Attachment
205 for (Device device : port.getDevices()) {
206 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
207 devEvt.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(), port.getNumber()));
208 // calling Discovery API to wipe from DB, etc.
209 removeDeviceEvent(devEvt);
210 }
211 Set<Link> links = new HashSet<>();
212 links.add(port.getOutgoingLink());
213 links.add(port.getIncomingLink());
214 for ( Link link : links) {
215 if (link == null ) {
216 continue;
217 }
218 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
219 // calling Discovery API to wipe from DB, etc.
220 removeLinkEvent(linkEvent);
221 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800222 return true;
223 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800224
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800225 private boolean prepareForAddLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800226 // Src/Dst Switch must exist
227 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
228 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
229 if ( srcSw == null || dstSw == null ) {
230 return false;
231 }
232 // Src/Dst Port must exist
233 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Jonathan Hart4c263272014-02-13 17:41:05 -0800234 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800235 if ( srcPort == null || dstPort == null ) {
236 return false;
237 }
238
239 // Prep: remove Device attachment on both Ports
240 for (Device device : srcPort.getDevices()) {
241 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
242 devEvt.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
243 // calling Discovery API to wipe from DB, etc.
244 removeDeviceEvent(devEvt);
245 }
246 for (Device device : dstPort.getDevices()) {
247 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
248 devEvt.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(), dstPort.getNumber()));
249 // calling Discovery API to wipe from DB, etc.
250 removeDeviceEvent(devEvt);
251 }
252
253 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800254 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800255
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800256 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800257 // Src/Dst Switch must exist
258 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
259 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
260 if ( srcSw == null || dstSw == null ) {
Jonathan Hart4c263272014-02-13 17:41:05 -0800261 log.warn("Rejecting addLink {} because switch doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800262 return false;
263 }
264 // Src/Dst Port must exist
265 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
266 Port dstPort = srcSw.getPort(linkEvt.getDst().number);
267 if ( srcPort == null || dstPort == null ) {
Jonathan Hart4c263272014-02-13 17:41:05 -0800268 log.warn("Rejecting addLink {} because port doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800269 return false;
270 }
Jonathan Hart4c263272014-02-13 17:41:05 -0800271
272 Link link = srcPort.getOutgoingLink();
273
274 if (link == null ||
275 !link.getDestinationPortNumber().equals(linkEvt.getDst().number)
276 || !link.getDestinationSwitchDpid().equals(linkEvt.getDst().dpid)) {
277 log.warn("Rejecting removeLink {} because link doesn't exist", linkEvt);
278 return false;
279 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800280
281 // Prep: None
282 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800283 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800284
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800285 /**
286 *
287 * @param deviceEvt Event will be modified to remove inapplicable attachemntPoints/ipAddress
288 * @return false if this event should be dropped.
289 */
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800290 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800291 boolean preconditionBroken = false;
292 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
293 for ( PortEvent.SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800294 // Attached Ports' Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800295 Switch sw = getSwitch(swp.dpid);
296 if ( sw == null ) {
297 preconditionBroken = true;
298 failedSwitchPort.add(swp);
299 continue;
300 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800301 // Attached Ports must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800302 Port port = sw.getPort(swp.number);
303 if ( port == null ) {
304 preconditionBroken = true;
305 failedSwitchPort.add(swp);
306 continue;
307 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800308 // Attached Ports must not have Link
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800309 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
310 preconditionBroken = true;
311 failedSwitchPort.add(swp);
312 continue;
313 }
314 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800315
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800316 // Rewriting event to exclude failed attachmentPoint
317 // XXX Assumption behind this is that inapplicable device event should
318 // be dropped, not deferred. If we decide to defer Device event,
319 // rewriting can become a problem
320 List<SwitchPort> attachmentPoints = deviceEvt.getAttachmentPoints();
321 attachmentPoints.removeAll(failedSwitchPort);
322 deviceEvt.setAttachmentPoints(attachmentPoints);
323
324 if ( deviceEvt.getAttachmentPoints().isEmpty() && deviceEvt.getIpAddresses().isEmpty() ) {
325 // XXX return false to represent: Nothing left to do for this event. Caller should drop event
326 return false;
327 }
328
329 // Should we return false to tell caller that the event was trimmed?
330 // if ( preconditionBroken ) {
331 // return false;
332 // }
333
334 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800335 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800336
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800337 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800338 // No show stopping precondition?
339 // Prep: none
Jonathan Hart22eb9882014-02-11 15:52:59 -0800340 return true;
341 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800342
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800343 /* ******************************
344 * NetworkGraphReplicationInterface methods
345 * ******************************/
346
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800347 @Override
348 public void putSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800349 // TODO who is in charge of ignoring event triggered by my self?
350 // This method or caller?
351 if (prepareForAddSwitchEvent(switchEvent)) {
352 putSwitch(switchEvent);
353 }
354 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800355 }
356
357 @Override
358 public void removeSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800359 // TODO who is in charge of ignoring event triggered by my self?
360 // This method or caller?
361 if (prepareForRemoveSwitchEvent(switchEvent)) {
362 removeSwitch(switchEvent);
363 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800364 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800365 }
366
367 @Override
368 public void putPortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800369 // TODO who is in charge of ignoring event triggered by my self?
370 // This method or caller?
371 if (prepareForAddPortEvent(portEvent)) {
372 putPort(portEvent);
373 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800374 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800375 }
376
377 @Override
378 public void removePortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800379 // TODO who is in charge of ignoring event triggered by my self?
380 // This method or caller?
381 if (prepareForRemovePortEvent(portEvent)) {
382 removePort(portEvent);
383 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800384 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800385 }
386
387 @Override
388 public void putLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800389 // TODO who is in charge of ignoring event triggered by my self?
390 // This method or caller?
391 if (prepareForAddLinkEvent(linkEvent)) {
392 putLink(linkEvent);
393 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800394 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800395 }
396
397 @Override
398 public void removeLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800399 // TODO who is in charge of ignoring event triggered by my self?
400 // This method or caller?
401 if (prepareForRemoveLinkEvent(linkEvent)) {
402 removeLink(linkEvent);
403 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800404 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800405 }
406
407 @Override
408 public void putDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800409 // TODO who is in charge of ignoring event triggered by my self?
410 // This method or caller?
411 if (prepareForAddDeviceEvent(deviceEvent)) {
412 putDevice(deviceEvent);
413 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800414 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800415 }
416
417 @Override
418 public void removeDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800419 // TODO who is in charge of ignoring event triggered by my self?
420 // This method or caller?
421 if (prepareForRemoveDeviceEvent(deviceEvent)) {
422 removeDevice(deviceEvent);
423 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800424 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800425 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800426
427 /* ************************************************
428 * Internal In-memory object mutation methods.
429 * ************************************************/
430
431 void putSwitch(SwitchEvent swEvt) {
432 if (swEvt == null) {
433 throw new IllegalArgumentException("Switch cannot be null");
434 }
435
436 Switch sw = switches.get(swEvt.getDpid());
437
438 if (sw == null) {
439 sw = new SwitchImpl(this, swEvt.getDpid());
440 Switch existing = switches.putIfAbsent(swEvt.getDpid(), sw);
441 if (existing != null) {
442 log.warn(
443 "Concurrent putSwitch not expected. Continuing updating {}",
444 existing);
445 sw = existing;
446 }
447 }
448
449 // Update when more attributes are added to Event object
450 // no attribute to update for now
451
452 // TODO handle child Port event properly for performance
453 for (PortEvent portEvt : swEvt.getPorts() ) {
454 putPort(portEvt);
455 }
456
457 }
458
459 void removeSwitch(SwitchEvent swEvt) {
460 if (swEvt == null) {
461 throw new IllegalArgumentException("Switch cannot be null");
462 }
463
464 // TODO handle child Port event properly for performance
465 for (PortEvent portEvt : swEvt.getPorts() ) {
466 removePort(portEvt);
467 }
468
469 Switch sw = switches.get(swEvt.getDpid());
470
471 if (sw == null) {
472 log.warn("Switch {} already removed, ignoring", swEvt);
473 return;
474 }
475
476 // Sanity check
477 if (!sw.getPorts().isEmpty()) {
478 log.warn(
479 "Ports on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
480 swEvt);
481 // XXX Should we remove Port?
482 }
483 if (!sw.getDevices().isEmpty()) {
484 log.warn(
485 "Devices on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
486 swEvt);
487 // XXX Should we remove Device to Switch relation?
488 }
489 if (!sw.getIncomingLinks().iterator().hasNext()) {
490 log.warn(
491 "IncomingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
492 swEvt);
493 // XXX Should we remove Link?
494 }
495 if (!sw.getOutgoingLinks().iterator().hasNext()) {
496 log.warn(
497 "OutgoingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
498 swEvt);
499 // XXX Should we remove Link?
500 }
501
502 boolean removed = switches.remove(swEvt.getDpid(), sw);
503 if (removed) {
504 log.warn(
505 "Switch instance was replaced concurrently while removing {}. Something is not right.",
506 sw);
507 }
508 }
509
510 void putPort(PortEvent portEvt) {
511 if (portEvt == null) {
512 throw new IllegalArgumentException("Port cannot be null");
513 }
514 Switch sw = switches.get(portEvt.getDpid());
515 if (sw == null) {
516 throw new BrokenInvariantException(String.format(
517 "Switch with dpid %s did not exist.",
518 new Dpid(portEvt.getDpid())));
519 }
520 Port p = sw.getPort(portEvt.getNumber());
521 PortImpl port = null;
522 if (p != null) {
523 port = getPortImpl(p);
524 }
525
526 if (port == null) {
527 port = new PortImpl(this, sw, portEvt.getNumber());
528 }
529
530 // TODO update attributes
531
532 SwitchImpl s = getSwitchImpl(sw);
533 s.addPort(port);
534 }
535
536 void removePort(PortEvent portEvt) {
537 if (portEvt == null) {
538 throw new IllegalArgumentException("Port cannot be null");
539 }
540
541 Switch sw = switches.get(portEvt.getDpid());
542 if (sw == null) {
543 log.warn("Parent Switch for Port {} already removed, ignoring", portEvt);
544 return;
545 }
546
547 Port p = sw.getPort(portEvt.getNumber());
548 if (p == null) {
549 log.warn("Port {} already removed, ignoring", portEvt);
550 return;
551 }
552
553 // check if there is something referring to this Port
554
555 if (!p.getDevices().iterator().hasNext()) {
556 log.warn(
557 "Devices on Port {} should be removed prior to removing Port. Removing Port anyways",
558 portEvt);
559 // XXX Should we remove Device to Port relation?
560 }
561 if (p.getIncomingLink() != null) {
562 log.warn(
563 "IncomingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
564 portEvt);
565 // XXX Should we remove Link?
566 }
567 if (p.getOutgoingLink() != null) {
568 log.warn(
569 "OutgoingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
570 portEvt);
571 // XXX Should we remove Link?
572 }
573
574 // remove Port from Switch
575 SwitchImpl s = getSwitchImpl(sw);
576 s.removePort(p);
577 }
578
579 void putLink(LinkEvent linkEvt) {
580 if (linkEvt == null) {
581 throw new IllegalArgumentException("Link cannot be null");
582 }
583
584 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
585 if (srcSw == null) {
586 throw new BrokenInvariantException(
587 String.format(
588 "Switch with dpid %s did not exist.",
589 new Dpid(linkEvt.getSrc().dpid)));
590 }
591
592 Switch dstSw = switches.get(linkEvt.getDst().dpid);
593 if (dstSw == null) {
594 throw new BrokenInvariantException(
595 String.format(
596 "Switch with dpid %s did not exist.",
597 new Dpid(linkEvt.getDst().dpid)));
598 }
599
600 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
601 if (srcPort == null) {
602 throw new BrokenInvariantException(
603 String.format(
604 "Src Port %s of a Link did not exist.",
605 linkEvt.getSrc() ));
606 }
607
608 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
609 if (dstPort == null) {
610 throw new BrokenInvariantException(
611 String.format(
612 "Dst Port %s of a Link did not exist.",
613 linkEvt.getDst() ));
614 }
615
616 // getting Link instance from destination port incoming Link
617 Link l = dstPort.getIncomingLink();
618 LinkImpl link = null;
619 assert( l == srcPort.getOutgoingLink() );
620 if (l != null) {
621 link = getLinkImpl(l);
622 }
623
624 if (link == null) {
625 link = new LinkImpl(this, srcPort, dstPort);
626 }
627
628
629 PortImpl dstPortMem = getPortImpl(dstPort);
630 PortImpl srcPortMem = getPortImpl(srcPort);
631
632 // Add Link first to avoid further Device addition
633
634 // add Link to Port
635 dstPortMem.setIncomingLink(link);
636 srcPortMem.setOutgoingLink(link);
637
638 // remove Device Pointing to Port if any
639 for(Device d : dstPortMem.getDevices() ) {
640 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, dstPort, linkEvt);
641 DeviceImpl dev = getDeviceImpl(d);
642 dev.removeAttachmentPoint(dstPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800643 // This implies that change is made to Device Object.
644 // sending Device attachment point removed event
645 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
646 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
647 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800648 }
649 dstPortMem.removeAllDevice();
650 for(Device d : srcPortMem.getDevices() ) {
651 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, srcPort, linkEvt);
652 DeviceImpl dev = getDeviceImpl(d);
653 dev.removeAttachmentPoint(srcPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800654 // This implies that change is made to Device Object.
655 // sending Device attachment point removed event
656 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
657 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
658 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800659 }
660 srcPortMem.removeAllDevice();
661
662 }
663
664 void removeLink(LinkEvent linkEvt) {
665 if (linkEvt == null) {
666 throw new IllegalArgumentException("Link cannot be null");
667 }
668
669 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
670 if (srcSw == null) {
671 log.warn("Src Switch for Link {} already removed, ignoring", linkEvt);
672 return;
673 }
674
675 Switch dstSw = switches.get(linkEvt.getDst().dpid);
676 if (dstSw == null) {
677 log.warn("Dst Switch for Link {} already removed, ignoring", linkEvt);
678 return;
679 }
680
681 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
682 if (srcPort == null) {
683 log.warn("Src Port for Link {} already removed, ignoring", linkEvt);
684 return;
685 }
686
687 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
688 if (dstPort == null) {
689 log.warn("Dst Port for Link {} already removed, ignoring", linkEvt);
690 return;
691 }
692
693 Link l = dstPort.getIncomingLink();
694 if ( l == null ) {
695 log.warn("Link {} already removed on destination Port", linkEvt);
696 }
697 l = srcPort.getOutgoingLink();
698 if ( l == null ) {
699 log.warn("Link {} already removed on src Port", linkEvt);
700 }
701
702 getPortImpl(dstPort).setIncomingLink(null);
703 getPortImpl(srcPort).setOutgoingLink(null);
704 }
705
706 // XXX Need to rework Device related
707 void putDevice(DeviceEvent deviceEvt) {
708 if (deviceEvt == null) {
709 throw new IllegalArgumentException("Device cannot be null");
710 }
711
712 Device device = getDeviceByMac(deviceEvt.getMac());
713 if ( device == null ) {
714 device = new DeviceImpl(this, deviceEvt.getMac());
715 Device existing = mac2Device.putIfAbsent(deviceEvt.getMac(), device);
716 if (existing != null) {
717 log.warn(
718 "Concurrent putDevice seems to be in action. Continuing updating {}",
719 existing);
720 device = existing;
721 }
722 }
723 DeviceImpl memDevice = getDeviceImpl(device);
724
725 // for each attachment point
726 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
727 // Attached Ports' Parent Switch must exist
728 Switch sw = getSwitch(swp.dpid);
729 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800730 log.warn("Switch for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800731 continue;
732 }
733 // Attached Ports must exist
734 Port port = sw.getPort(swp.number);
735 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800736 log.warn("Port for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800737 continue;
738 }
739 // Attached Ports must not have Link
740 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
741 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.", port.getOutgoingLink(), port.getIncomingLink());
742 continue;
743 }
744
745 // finally add Device <-> Port on In-memory structure
746 PortImpl memPort = getPortImpl(port);
747 memPort.addDevice(device);
748 memDevice.addAttachmentPoint(port);
749 }
750
751 // for each IP address
752 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
753 // Add Device -> IP
754 memDevice.addIpAddress(ipAddr);
755
756 // Add IP -> Set<Device>
757 boolean updated = false;
758 do {
759 Set<Device> devices = this.addr2Device.get(ipAddr);
760 if ( devices == null ) {
761 devices = new HashSet<>();
762 Set<Device> existing = this.addr2Device.putIfAbsent(ipAddr, devices);
763 if ( existing == null ) {
764 // success
765 updated = true;
766 }
767 } else {
768 Set<Device> updateDevices = new HashSet<>(devices);
769 updateDevices.add(device);
770 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
771 }
772 if (!updated) {
773 log.debug("Collision detected, updating IP to Device mapping retrying.");
774 }
775 } while( !updated );
776 }
777 }
778
779 void removeDevice(DeviceEvent deviceEvt) {
780 if (deviceEvt == null) {
781 throw new IllegalArgumentException("Device cannot be null");
782 }
783
784 Device device = getDeviceByMac(deviceEvt.getMac());
785 if ( device == null ) {
786 log.warn("Device {} already removed, ignoring", deviceEvt);
787 return;
788 }
789 DeviceImpl memDevice = getDeviceImpl(device);
790
791 // for each attachment point
792 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
793 // Attached Ports' Parent Switch must exist
794 Switch sw = getSwitch(swp.dpid);
795 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800796 log.warn("Switch for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800797 continue;
798 }
799 // Attached Ports must exist
800 Port port = sw.getPort(swp.number);
801 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800802 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800803 continue;
804 }
805
806 // finally remove Device <-> Port on In-memory structure
807 PortImpl memPort = getPortImpl(port);
808 memPort.removeDevice(device);
809 memDevice.removeAttachmentPoint(port);
810 }
811
812 // for each IP address
813 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
814 // Remove Device -> IP
815 memDevice.removeIpAddress(ipAddr);
816
817 // Remove IP -> Set<Device>
818 boolean updated = false;
819 do {
820 Set<Device> devices = this.addr2Device.get(ipAddr);
821 if ( devices == null ) {
822 // already empty set, nothing to do
823 updated = true;
824 } else {
825 Set<Device> updateDevices = new HashSet<>(devices);
826 updateDevices.remove(device);
827 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
828 }
829 if (!updated) {
830 log.debug("Collision detected, updating IP to Device mapping retrying.");
831 }
832 } while( !updated );
833 }
834 }
835
836 private SwitchImpl getSwitchImpl(Switch sw) {
837 if (sw instanceof SwitchImpl) {
838 return (SwitchImpl) sw;
839 }
840 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
841 }
842
843 private PortImpl getPortImpl(Port p) {
844 if (p instanceof PortImpl) {
845 return (PortImpl) p;
846 }
847 throw new ClassCastException("PortImpl expected, but found: " + p);
848 }
849
850 private LinkImpl getLinkImpl(Link l) {
851 if (l instanceof LinkImpl) {
852 return (LinkImpl) l;
853 }
854 throw new ClassCastException("LinkImpl expected, but found: " + l);
855 }
856
857 private DeviceImpl getDeviceImpl(Device d) {
858 if (d instanceof DeviceImpl) {
859 return (DeviceImpl) d;
860 }
861 throw new ClassCastException("DeviceImpl expected, but found: " + d);
862 }
863
864 @Deprecated
865 public void loadWholeTopologyFromDB() {
866 // XXX clear everything first?
867
868 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
869 if ( sw.getStatus() != RCSwitch.STATUS.ACTIVE ) {
870 continue;
871 }
872 putSwitchReplicationEvent(new SwitchEvent(sw.getDpid()));
873 }
874
875 for (RCPort p : RCPort.getAllPorts()) {
876 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
877 continue;
878 }
879 putPortReplicationEvent(new PortEvent(p.getDpid(), p.getNumber() ));
880 }
881
882 // TODO Is Device going to be in DB? If so, read from DB.
883 // for (RCDevice d : RCDevice.getAllDevices()) {
884 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
885 // for (byte[] portId : d.getAllPortIds() ) {
886 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
887 // }
888 // }
889
890 for (RCLink l : RCLink.getAllLinks()) {
891 putLinkReplicationEvent( new LinkEvent(l.getSrc().dpid, l.getSrc().number, l.getDst().dpid, l.getDst().number));
892 }
893 }
Jonathan Hart062a2e82014-02-03 09:41:57 -0800894}