blob: 34e8d5176236178e452da986265e24c5b2bee829 [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 }
Jonathan Hart22eb9882014-02-11 15:52:59 -080093 }
94
95 @Override
96 public void removePortEvent(PortEvent portEvent) {
Jonathan Hart4c263272014-02-13 17:41:05 -080097 if (prepareForRemovePortEvent(portEvent)) {
98 datastore.deactivatePort(portEvent);
99 removePort(portEvent);
100 // TODO send out notification
101 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800102 }
103
104 @Override
105 public void putLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800106 if (prepareForAddLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800107 datastore.addLink(linkEvent);
108 putLink(linkEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800109 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -0800110 }
111 // TODO handle invariant violation
112 }
113
114 @Override
115 public void removeLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800116 if (prepareForRemoveLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800117 datastore.removeLink(linkEvent);
118 removeLink(linkEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800119 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -0800120 }
121 // TODO handle invariant violation
122 }
123
124 @Override
Yuta HIGUCHI0be4a662014-02-11 18:01:28 -0800125 public void putDeviceEvent(DeviceEvent device) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800126 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800127 // TODO Auto-generated method stub
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800128
Jonathan Hart22eb9882014-02-11 15:52:59 -0800129 }
130
131 @Override
132 public void removeDeviceEvent(DeviceEvent deviceEvent) {
133 // TODO Auto-generated method stub
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800134
Jonathan Hart22eb9882014-02-11 15:52:59 -0800135 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800136
Jonathan Hart22eb9882014-02-11 15:52:59 -0800137 /* *****************
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800138 * Internal methods to maintain invariants of the network graph
Jonathan Hart22eb9882014-02-11 15:52:59 -0800139 * *****************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800140
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800141 /**
142 *
143 * @param swEvt
144 * @return true if ready to accept event.
145 */
146 private boolean prepareForAddSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800147 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800148 // Prep: remove(deactivate) Ports on Switch, which is not on event
149 removePortsNotOnEvent(swEvt);
150 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800151 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800152
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800153 private boolean prepareForRemoveSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800154 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800155 // Prep: remove(deactivate) Ports on Switch, which is not on event
156 // XXX may be remove switch should imply wipe all ports
157 removePortsNotOnEvent(swEvt);
158 return true;
159 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800160
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800161 private void removePortsNotOnEvent(SwitchEvent swEvt) {
162 Switch sw = switches.get( swEvt.getDpid() );
163 if ( sw != null ) {
164 Set<Long> port_noOnEvent = new HashSet<>();
165 for( PortEvent portEvent : swEvt.getPorts()) {
166 port_noOnEvent.add(portEvent.getNumber());
167 }
168 // Existing ports not on event should be removed.
169 // TODO Should batch eventually for performance?
170 for( Port p : sw.getPorts() ) {
171 if ( !port_noOnEvent.contains(p.getNumber()) ) {
172 PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
173 // calling Discovery removePort() API to wipe from DB, etc.
174 removePortEvent(rmEvent);
175 }
176 }
177 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800178 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800179
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800180 private boolean prepareForAddPortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800181 // Parent Switch must exist
182 if ( getSwitch(portEvt.getDpid()) == null) {
183 return false;
184 }
185 // Prep: None
Jonathan Hart22eb9882014-02-11 15:52:59 -0800186 return true;
187 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800188
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800189 private boolean prepareForRemovePortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800190 // Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800191 Switch sw = getSwitch(portEvt.getDpid());
192 if ( sw == null ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800193 return false;
194 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800195 Port port = sw.getPort(portEvt.getNumber());
196 if ( port == null ) {
197 log.debug("Port already removed? {}", portEvt);
198 // let it pass
199 return true;
200 }
201
202 // Prep: Remove Link and Device Attachment
203 for (Device device : port.getDevices()) {
204 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
205 devEvt.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(), port.getNumber()));
206 // calling Discovery API to wipe from DB, etc.
207 removeDeviceEvent(devEvt);
208 }
209 Set<Link> links = new HashSet<>();
210 links.add(port.getOutgoingLink());
211 links.add(port.getIncomingLink());
212 for ( Link link : links) {
213 if (link == null ) {
214 continue;
215 }
216 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
217 // calling Discovery API to wipe from DB, etc.
218 removeLinkEvent(linkEvent);
219 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800220 return true;
221 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800222
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800223 private boolean prepareForAddLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800224 // Src/Dst Switch must exist
225 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
226 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
227 if ( srcSw == null || dstSw == null ) {
228 return false;
229 }
230 // Src/Dst Port must exist
231 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Jonathan Hart4c263272014-02-13 17:41:05 -0800232 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800233 if ( srcPort == null || dstPort == null ) {
234 return false;
235 }
236
237 // Prep: remove Device attachment on both Ports
238 for (Device device : srcPort.getDevices()) {
239 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
240 devEvt.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
241 // calling Discovery API to wipe from DB, etc.
242 removeDeviceEvent(devEvt);
243 }
244 for (Device device : dstPort.getDevices()) {
245 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
246 devEvt.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(), dstPort.getNumber()));
247 // calling Discovery API to wipe from DB, etc.
248 removeDeviceEvent(devEvt);
249 }
250
251 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800252 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800253
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800254 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800255 // Src/Dst Switch must exist
256 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
257 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
258 if ( srcSw == null || dstSw == null ) {
Jonathan Hart4c263272014-02-13 17:41:05 -0800259 log.warn("Rejecting addLink {} because switch doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800260 return false;
261 }
262 // Src/Dst Port must exist
263 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
264 Port dstPort = srcSw.getPort(linkEvt.getDst().number);
265 if ( srcPort == null || dstPort == null ) {
Jonathan Hart4c263272014-02-13 17:41:05 -0800266 log.warn("Rejecting addLink {} because port doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800267 return false;
268 }
Jonathan Hart4c263272014-02-13 17:41:05 -0800269
270 Link link = srcPort.getOutgoingLink();
271
272 if (link == null ||
273 !link.getDestinationPortNumber().equals(linkEvt.getDst().number)
274 || !link.getDestinationSwitchDpid().equals(linkEvt.getDst().dpid)) {
275 log.warn("Rejecting removeLink {} because link doesn't exist", linkEvt);
276 return false;
277 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800278
279 // Prep: None
280 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800281 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800282
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800283 /**
284 *
285 * @param deviceEvt Event will be modified to remove inapplicable attachemntPoints/ipAddress
286 * @return false if this event should be dropped.
287 */
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800288 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800289 boolean preconditionBroken = false;
290 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
291 for ( PortEvent.SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800292 // Attached Ports' Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800293 Switch sw = getSwitch(swp.dpid);
294 if ( sw == null ) {
295 preconditionBroken = true;
296 failedSwitchPort.add(swp);
297 continue;
298 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800299 // Attached Ports must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800300 Port port = sw.getPort(swp.number);
301 if ( port == null ) {
302 preconditionBroken = true;
303 failedSwitchPort.add(swp);
304 continue;
305 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800306 // Attached Ports must not have Link
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800307 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
308 preconditionBroken = true;
309 failedSwitchPort.add(swp);
310 continue;
311 }
312 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800313
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800314 // Rewriting event to exclude failed attachmentPoint
315 // XXX Assumption behind this is that inapplicable device event should
316 // be dropped, not deferred. If we decide to defer Device event,
317 // rewriting can become a problem
318 List<SwitchPort> attachmentPoints = deviceEvt.getAttachmentPoints();
319 attachmentPoints.removeAll(failedSwitchPort);
320 deviceEvt.setAttachmentPoints(attachmentPoints);
321
322 if ( deviceEvt.getAttachmentPoints().isEmpty() && deviceEvt.getIpAddresses().isEmpty() ) {
323 // XXX return false to represent: Nothing left to do for this event. Caller should drop event
324 return false;
325 }
326
327 // Should we return false to tell caller that the event was trimmed?
328 // if ( preconditionBroken ) {
329 // return false;
330 // }
331
332 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800333 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800334
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800335 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800336 // No show stopping precondition?
337 // Prep: none
Jonathan Hart22eb9882014-02-11 15:52:59 -0800338 return true;
339 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800340
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800341 /* ******************************
342 * NetworkGraphReplicationInterface methods
343 * ******************************/
344
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800345 @Override
346 public void putSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800347 // TODO who is in charge of ignoring event triggered by my self?
348 // This method or caller?
349 if (prepareForAddSwitchEvent(switchEvent)) {
350 putSwitch(switchEvent);
351 }
352 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800353 }
354
355 @Override
356 public void removeSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800357 // TODO who is in charge of ignoring event triggered by my self?
358 // This method or caller?
359 if (prepareForRemoveSwitchEvent(switchEvent)) {
360 removeSwitch(switchEvent);
361 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800362 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800363 }
364
365 @Override
366 public void putPortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800367 // TODO who is in charge of ignoring event triggered by my self?
368 // This method or caller?
369 if (prepareForAddPortEvent(portEvent)) {
370 putPort(portEvent);
371 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800372 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800373 }
374
375 @Override
376 public void removePortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800377 // TODO who is in charge of ignoring event triggered by my self?
378 // This method or caller?
379 if (prepareForRemovePortEvent(portEvent)) {
380 removePort(portEvent);
381 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800382 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800383 }
384
385 @Override
386 public void putLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800387 // TODO who is in charge of ignoring event triggered by my self?
388 // This method or caller?
389 if (prepareForAddLinkEvent(linkEvent)) {
390 putLink(linkEvent);
391 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800392 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800393 }
394
395 @Override
396 public void removeLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800397 // TODO who is in charge of ignoring event triggered by my self?
398 // This method or caller?
399 if (prepareForRemoveLinkEvent(linkEvent)) {
400 removeLink(linkEvent);
401 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800402 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800403 }
404
405 @Override
406 public void putDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800407 // TODO who is in charge of ignoring event triggered by my self?
408 // This method or caller?
409 if (prepareForAddDeviceEvent(deviceEvent)) {
410 putDevice(deviceEvent);
411 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800412 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800413 }
414
415 @Override
416 public void removeDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800417 // TODO who is in charge of ignoring event triggered by my self?
418 // This method or caller?
419 if (prepareForRemoveDeviceEvent(deviceEvent)) {
420 removeDevice(deviceEvent);
421 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800422 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800423 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800424
425 /* ************************************************
426 * Internal In-memory object mutation methods.
427 * ************************************************/
428
429 void putSwitch(SwitchEvent swEvt) {
430 if (swEvt == null) {
431 throw new IllegalArgumentException("Switch cannot be null");
432 }
433
434 Switch sw = switches.get(swEvt.getDpid());
435
436 if (sw == null) {
437 sw = new SwitchImpl(this, swEvt.getDpid());
438 Switch existing = switches.putIfAbsent(swEvt.getDpid(), sw);
439 if (existing != null) {
440 log.warn(
441 "Concurrent putSwitch not expected. Continuing updating {}",
442 existing);
443 sw = existing;
444 }
445 }
446
447 // Update when more attributes are added to Event object
448 // no attribute to update for now
449
450 // TODO handle child Port event properly for performance
451 for (PortEvent portEvt : swEvt.getPorts() ) {
452 putPort(portEvt);
453 }
454
455 }
456
457 void removeSwitch(SwitchEvent swEvt) {
458 if (swEvt == null) {
459 throw new IllegalArgumentException("Switch cannot be null");
460 }
461
462 // TODO handle child Port event properly for performance
463 for (PortEvent portEvt : swEvt.getPorts() ) {
464 removePort(portEvt);
465 }
466
467 Switch sw = switches.get(swEvt.getDpid());
468
469 if (sw == null) {
470 log.warn("Switch {} already removed, ignoring", swEvt);
471 return;
472 }
473
474 // Sanity check
475 if (!sw.getPorts().isEmpty()) {
476 log.warn(
477 "Ports on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
478 swEvt);
479 // XXX Should we remove Port?
480 }
481 if (!sw.getDevices().isEmpty()) {
482 log.warn(
483 "Devices on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
484 swEvt);
485 // XXX Should we remove Device to Switch relation?
486 }
487 if (!sw.getIncomingLinks().iterator().hasNext()) {
488 log.warn(
489 "IncomingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
490 swEvt);
491 // XXX Should we remove Link?
492 }
493 if (!sw.getOutgoingLinks().iterator().hasNext()) {
494 log.warn(
495 "OutgoingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
496 swEvt);
497 // XXX Should we remove Link?
498 }
499
500 boolean removed = switches.remove(swEvt.getDpid(), sw);
501 if (removed) {
502 log.warn(
503 "Switch instance was replaced concurrently while removing {}. Something is not right.",
504 sw);
505 }
506 }
507
508 void putPort(PortEvent portEvt) {
509 if (portEvt == null) {
510 throw new IllegalArgumentException("Port cannot be null");
511 }
512 Switch sw = switches.get(portEvt.getDpid());
513 if (sw == null) {
514 throw new BrokenInvariantException(String.format(
515 "Switch with dpid %s did not exist.",
516 new Dpid(portEvt.getDpid())));
517 }
518 Port p = sw.getPort(portEvt.getNumber());
519 PortImpl port = null;
520 if (p != null) {
521 port = getPortImpl(p);
522 }
523
524 if (port == null) {
525 port = new PortImpl(this, sw, portEvt.getNumber());
526 }
527
528 // TODO update attributes
529
530 SwitchImpl s = getSwitchImpl(sw);
531 s.addPort(port);
532 }
533
534 void removePort(PortEvent portEvt) {
535 if (portEvt == null) {
536 throw new IllegalArgumentException("Port cannot be null");
537 }
538
539 Switch sw = switches.get(portEvt.getDpid());
540 if (sw == null) {
541 log.warn("Parent Switch for Port {} already removed, ignoring", portEvt);
542 return;
543 }
544
545 Port p = sw.getPort(portEvt.getNumber());
546 if (p == null) {
547 log.warn("Port {} already removed, ignoring", portEvt);
548 return;
549 }
550
551 // check if there is something referring to this Port
552
553 if (!p.getDevices().iterator().hasNext()) {
554 log.warn(
555 "Devices on Port {} should be removed prior to removing Port. Removing Port anyways",
556 portEvt);
557 // XXX Should we remove Device to Port relation?
558 }
559 if (p.getIncomingLink() != null) {
560 log.warn(
561 "IncomingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
562 portEvt);
563 // XXX Should we remove Link?
564 }
565 if (p.getOutgoingLink() != null) {
566 log.warn(
567 "OutgoingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
568 portEvt);
569 // XXX Should we remove Link?
570 }
571
572 // remove Port from Switch
573 SwitchImpl s = getSwitchImpl(sw);
574 s.removePort(p);
575 }
576
577 void putLink(LinkEvent linkEvt) {
578 if (linkEvt == null) {
579 throw new IllegalArgumentException("Link cannot be null");
580 }
581
582 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
583 if (srcSw == null) {
584 throw new BrokenInvariantException(
585 String.format(
586 "Switch with dpid %s did not exist.",
587 new Dpid(linkEvt.getSrc().dpid)));
588 }
589
590 Switch dstSw = switches.get(linkEvt.getDst().dpid);
591 if (dstSw == null) {
592 throw new BrokenInvariantException(
593 String.format(
594 "Switch with dpid %s did not exist.",
595 new Dpid(linkEvt.getDst().dpid)));
596 }
597
598 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
599 if (srcPort == null) {
600 throw new BrokenInvariantException(
601 String.format(
602 "Src Port %s of a Link did not exist.",
603 linkEvt.getSrc() ));
604 }
605
606 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
607 if (dstPort == null) {
608 throw new BrokenInvariantException(
609 String.format(
610 "Dst Port %s of a Link did not exist.",
611 linkEvt.getDst() ));
612 }
613
614 // getting Link instance from destination port incoming Link
615 Link l = dstPort.getIncomingLink();
616 LinkImpl link = null;
617 assert( l == srcPort.getOutgoingLink() );
618 if (l != null) {
619 link = getLinkImpl(l);
620 }
621
622 if (link == null) {
623 link = new LinkImpl(this, srcPort, dstPort);
624 }
625
626
627 PortImpl dstPortMem = getPortImpl(dstPort);
628 PortImpl srcPortMem = getPortImpl(srcPort);
629
630 // Add Link first to avoid further Device addition
631
632 // add Link to Port
633 dstPortMem.setIncomingLink(link);
634 srcPortMem.setOutgoingLink(link);
635
636 // remove Device Pointing to Port if any
637 for(Device d : dstPortMem.getDevices() ) {
638 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, dstPort, linkEvt);
639 DeviceImpl dev = getDeviceImpl(d);
640 dev.removeAttachmentPoint(dstPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800641 // This implies that change is made to Device Object.
642 // sending Device attachment point removed event
643 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
644 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
645 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800646 }
647 dstPortMem.removeAllDevice();
648 for(Device d : srcPortMem.getDevices() ) {
649 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, srcPort, linkEvt);
650 DeviceImpl dev = getDeviceImpl(d);
651 dev.removeAttachmentPoint(srcPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800652 // This implies that change is made to Device Object.
653 // sending Device attachment point removed event
654 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
655 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
656 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800657 }
658 srcPortMem.removeAllDevice();
659
660 }
661
662 void removeLink(LinkEvent linkEvt) {
663 if (linkEvt == null) {
664 throw new IllegalArgumentException("Link cannot be null");
665 }
666
667 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
668 if (srcSw == null) {
669 log.warn("Src Switch for Link {} already removed, ignoring", linkEvt);
670 return;
671 }
672
673 Switch dstSw = switches.get(linkEvt.getDst().dpid);
674 if (dstSw == null) {
675 log.warn("Dst Switch for Link {} already removed, ignoring", linkEvt);
676 return;
677 }
678
679 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
680 if (srcPort == null) {
681 log.warn("Src Port for Link {} already removed, ignoring", linkEvt);
682 return;
683 }
684
685 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
686 if (dstPort == null) {
687 log.warn("Dst Port for Link {} already removed, ignoring", linkEvt);
688 return;
689 }
690
691 Link l = dstPort.getIncomingLink();
692 if ( l == null ) {
693 log.warn("Link {} already removed on destination Port", linkEvt);
694 }
695 l = srcPort.getOutgoingLink();
696 if ( l == null ) {
697 log.warn("Link {} already removed on src Port", linkEvt);
698 }
699
700 getPortImpl(dstPort).setIncomingLink(null);
701 getPortImpl(srcPort).setOutgoingLink(null);
702 }
703
704 // XXX Need to rework Device related
705 void putDevice(DeviceEvent deviceEvt) {
706 if (deviceEvt == null) {
707 throw new IllegalArgumentException("Device cannot be null");
708 }
709
710 Device device = getDeviceByMac(deviceEvt.getMac());
711 if ( device == null ) {
712 device = new DeviceImpl(this, deviceEvt.getMac());
713 Device existing = mac2Device.putIfAbsent(deviceEvt.getMac(), device);
714 if (existing != null) {
715 log.warn(
716 "Concurrent putDevice seems to be in action. Continuing updating {}",
717 existing);
718 device = existing;
719 }
720 }
721 DeviceImpl memDevice = getDeviceImpl(device);
722
723 // for each attachment point
724 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
725 // Attached Ports' Parent Switch must exist
726 Switch sw = getSwitch(swp.dpid);
727 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800728 log.warn("Switch for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800729 continue;
730 }
731 // Attached Ports must exist
732 Port port = sw.getPort(swp.number);
733 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800734 log.warn("Port for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800735 continue;
736 }
737 // Attached Ports must not have Link
738 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
739 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.", port.getOutgoingLink(), port.getIncomingLink());
740 continue;
741 }
742
743 // finally add Device <-> Port on In-memory structure
744 PortImpl memPort = getPortImpl(port);
745 memPort.addDevice(device);
746 memDevice.addAttachmentPoint(port);
747 }
748
749 // for each IP address
750 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
751 // Add Device -> IP
752 memDevice.addIpAddress(ipAddr);
753
754 // Add IP -> Set<Device>
755 boolean updated = false;
756 do {
757 Set<Device> devices = this.addr2Device.get(ipAddr);
758 if ( devices == null ) {
759 devices = new HashSet<>();
760 Set<Device> existing = this.addr2Device.putIfAbsent(ipAddr, devices);
761 if ( existing == null ) {
762 // success
763 updated = true;
764 }
765 } else {
766 Set<Device> updateDevices = new HashSet<>(devices);
767 updateDevices.add(device);
768 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
769 }
770 if (!updated) {
771 log.debug("Collision detected, updating IP to Device mapping retrying.");
772 }
773 } while( !updated );
774 }
775 }
776
777 void removeDevice(DeviceEvent deviceEvt) {
778 if (deviceEvt == null) {
779 throw new IllegalArgumentException("Device cannot be null");
780 }
781
782 Device device = getDeviceByMac(deviceEvt.getMac());
783 if ( device == null ) {
784 log.warn("Device {} already removed, ignoring", deviceEvt);
785 return;
786 }
787 DeviceImpl memDevice = getDeviceImpl(device);
788
789 // for each attachment point
790 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
791 // Attached Ports' Parent Switch must exist
792 Switch sw = getSwitch(swp.dpid);
793 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800794 log.warn("Switch for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800795 continue;
796 }
797 // Attached Ports must exist
798 Port port = sw.getPort(swp.number);
799 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800800 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800801 continue;
802 }
803
804 // finally remove Device <-> Port on In-memory structure
805 PortImpl memPort = getPortImpl(port);
806 memPort.removeDevice(device);
807 memDevice.removeAttachmentPoint(port);
808 }
809
810 // for each IP address
811 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
812 // Remove Device -> IP
813 memDevice.removeIpAddress(ipAddr);
814
815 // Remove IP -> Set<Device>
816 boolean updated = false;
817 do {
818 Set<Device> devices = this.addr2Device.get(ipAddr);
819 if ( devices == null ) {
820 // already empty set, nothing to do
821 updated = true;
822 } else {
823 Set<Device> updateDevices = new HashSet<>(devices);
824 updateDevices.remove(device);
825 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
826 }
827 if (!updated) {
828 log.debug("Collision detected, updating IP to Device mapping retrying.");
829 }
830 } while( !updated );
831 }
832 }
833
834 private SwitchImpl getSwitchImpl(Switch sw) {
835 if (sw instanceof SwitchImpl) {
836 return (SwitchImpl) sw;
837 }
838 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
839 }
840
841 private PortImpl getPortImpl(Port p) {
842 if (p instanceof PortImpl) {
843 return (PortImpl) p;
844 }
845 throw new ClassCastException("PortImpl expected, but found: " + p);
846 }
847
848 private LinkImpl getLinkImpl(Link l) {
849 if (l instanceof LinkImpl) {
850 return (LinkImpl) l;
851 }
852 throw new ClassCastException("LinkImpl expected, but found: " + l);
853 }
854
855 private DeviceImpl getDeviceImpl(Device d) {
856 if (d instanceof DeviceImpl) {
857 return (DeviceImpl) d;
858 }
859 throw new ClassCastException("DeviceImpl expected, but found: " + d);
860 }
861
862 @Deprecated
863 public void loadWholeTopologyFromDB() {
864 // XXX clear everything first?
865
866 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
867 if ( sw.getStatus() != RCSwitch.STATUS.ACTIVE ) {
868 continue;
869 }
870 putSwitchReplicationEvent(new SwitchEvent(sw.getDpid()));
871 }
872
873 for (RCPort p : RCPort.getAllPorts()) {
874 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
875 continue;
876 }
877 putPortReplicationEvent(new PortEvent(p.getDpid(), p.getNumber() ));
878 }
879
880 // TODO Is Device going to be in DB? If so, read from DB.
881 // for (RCDevice d : RCDevice.getAllDevices()) {
882 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
883 // for (byte[] portId : d.getAllPortIds() ) {
884 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
885 // }
886 // }
887
888 for (RCLink l : RCLink.getAllLinks()) {
889 putLinkReplicationEvent( new LinkEvent(l.getSrc().dpid, l.getSrc().number, l.getDst().dpid, l.getDst().number));
890 }
891 }
Jonathan Hart062a2e82014-02-03 09:41:57 -0800892}