blob: 1c342e0401b3342ef38ffa31392fac828bb21e1c [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);
641 // XXX This implies that change is made to Device Object,
642 // which need to be written to DB, how should that be done?
643 // should we write here or ignore and leave DB in inconsistent state?
644 }
645 dstPortMem.removeAllDevice();
646 for(Device d : srcPortMem.getDevices() ) {
647 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, srcPort, linkEvt);
648 DeviceImpl dev = getDeviceImpl(d);
649 dev.removeAttachmentPoint(srcPort);
650 // XXX This implies that change is made to Device Object,
651 // which need to be written to DB, how should that be done?
652 // should we write here or ignore and leave DB in inconsistent state?
653 }
654 srcPortMem.removeAllDevice();
655
656 }
657
658 void removeLink(LinkEvent linkEvt) {
659 if (linkEvt == null) {
660 throw new IllegalArgumentException("Link cannot be null");
661 }
662
663 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
664 if (srcSw == null) {
665 log.warn("Src Switch for Link {} already removed, ignoring", linkEvt);
666 return;
667 }
668
669 Switch dstSw = switches.get(linkEvt.getDst().dpid);
670 if (dstSw == null) {
671 log.warn("Dst Switch for Link {} already removed, ignoring", linkEvt);
672 return;
673 }
674
675 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
676 if (srcPort == null) {
677 log.warn("Src Port for Link {} already removed, ignoring", linkEvt);
678 return;
679 }
680
681 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
682 if (dstPort == null) {
683 log.warn("Dst Port for Link {} already removed, ignoring", linkEvt);
684 return;
685 }
686
687 Link l = dstPort.getIncomingLink();
688 if ( l == null ) {
689 log.warn("Link {} already removed on destination Port", linkEvt);
690 }
691 l = srcPort.getOutgoingLink();
692 if ( l == null ) {
693 log.warn("Link {} already removed on src Port", linkEvt);
694 }
695
696 getPortImpl(dstPort).setIncomingLink(null);
697 getPortImpl(srcPort).setOutgoingLink(null);
698 }
699
700 // XXX Need to rework Device related
701 void putDevice(DeviceEvent deviceEvt) {
702 if (deviceEvt == null) {
703 throw new IllegalArgumentException("Device cannot be null");
704 }
705
706 Device device = getDeviceByMac(deviceEvt.getMac());
707 if ( device == null ) {
708 device = new DeviceImpl(this, deviceEvt.getMac());
709 Device existing = mac2Device.putIfAbsent(deviceEvt.getMac(), device);
710 if (existing != null) {
711 log.warn(
712 "Concurrent putDevice seems to be in action. Continuing updating {}",
713 existing);
714 device = existing;
715 }
716 }
717 DeviceImpl memDevice = getDeviceImpl(device);
718
719 // for each attachment point
720 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
721 // Attached Ports' Parent Switch must exist
722 Switch sw = getSwitch(swp.dpid);
723 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800724 log.warn("Switch for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800725 continue;
726 }
727 // Attached Ports must exist
728 Port port = sw.getPort(swp.number);
729 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800730 log.warn("Port for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800731 continue;
732 }
733 // Attached Ports must not have Link
734 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
735 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.", port.getOutgoingLink(), port.getIncomingLink());
736 continue;
737 }
738
739 // finally add Device <-> Port on In-memory structure
740 PortImpl memPort = getPortImpl(port);
741 memPort.addDevice(device);
742 memDevice.addAttachmentPoint(port);
743 }
744
745 // for each IP address
746 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
747 // Add Device -> IP
748 memDevice.addIpAddress(ipAddr);
749
750 // Add IP -> Set<Device>
751 boolean updated = false;
752 do {
753 Set<Device> devices = this.addr2Device.get(ipAddr);
754 if ( devices == null ) {
755 devices = new HashSet<>();
756 Set<Device> existing = this.addr2Device.putIfAbsent(ipAddr, devices);
757 if ( existing == null ) {
758 // success
759 updated = true;
760 }
761 } else {
762 Set<Device> updateDevices = new HashSet<>(devices);
763 updateDevices.add(device);
764 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
765 }
766 if (!updated) {
767 log.debug("Collision detected, updating IP to Device mapping retrying.");
768 }
769 } while( !updated );
770 }
771 }
772
773 void removeDevice(DeviceEvent deviceEvt) {
774 if (deviceEvt == null) {
775 throw new IllegalArgumentException("Device cannot be null");
776 }
777
778 Device device = getDeviceByMac(deviceEvt.getMac());
779 if ( device == null ) {
780 log.warn("Device {} already removed, ignoring", deviceEvt);
781 return;
782 }
783 DeviceImpl memDevice = getDeviceImpl(device);
784
785 // for each attachment point
786 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
787 // Attached Ports' Parent Switch must exist
788 Switch sw = getSwitch(swp.dpid);
789 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800790 log.warn("Switch for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800791 continue;
792 }
793 // Attached Ports must exist
794 Port port = sw.getPort(swp.number);
795 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800796 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800797 continue;
798 }
799
800 // finally remove Device <-> Port on In-memory structure
801 PortImpl memPort = getPortImpl(port);
802 memPort.removeDevice(device);
803 memDevice.removeAttachmentPoint(port);
804 }
805
806 // for each IP address
807 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
808 // Remove Device -> IP
809 memDevice.removeIpAddress(ipAddr);
810
811 // Remove IP -> Set<Device>
812 boolean updated = false;
813 do {
814 Set<Device> devices = this.addr2Device.get(ipAddr);
815 if ( devices == null ) {
816 // already empty set, nothing to do
817 updated = true;
818 } else {
819 Set<Device> updateDevices = new HashSet<>(devices);
820 updateDevices.remove(device);
821 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
822 }
823 if (!updated) {
824 log.debug("Collision detected, updating IP to Device mapping retrying.");
825 }
826 } while( !updated );
827 }
828 }
829
830 private SwitchImpl getSwitchImpl(Switch sw) {
831 if (sw instanceof SwitchImpl) {
832 return (SwitchImpl) sw;
833 }
834 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
835 }
836
837 private PortImpl getPortImpl(Port p) {
838 if (p instanceof PortImpl) {
839 return (PortImpl) p;
840 }
841 throw new ClassCastException("PortImpl expected, but found: " + p);
842 }
843
844 private LinkImpl getLinkImpl(Link l) {
845 if (l instanceof LinkImpl) {
846 return (LinkImpl) l;
847 }
848 throw new ClassCastException("LinkImpl expected, but found: " + l);
849 }
850
851 private DeviceImpl getDeviceImpl(Device d) {
852 if (d instanceof DeviceImpl) {
853 return (DeviceImpl) d;
854 }
855 throw new ClassCastException("DeviceImpl expected, but found: " + d);
856 }
857
858 @Deprecated
859 public void loadWholeTopologyFromDB() {
860 // XXX clear everything first?
861
862 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
863 if ( sw.getStatus() != RCSwitch.STATUS.ACTIVE ) {
864 continue;
865 }
866 putSwitchReplicationEvent(new SwitchEvent(sw.getDpid()));
867 }
868
869 for (RCPort p : RCPort.getAllPorts()) {
870 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
871 continue;
872 }
873 putPortReplicationEvent(new PortEvent(p.getDpid(), p.getNumber() ));
874 }
875
876 // TODO Is Device going to be in DB? If so, read from DB.
877 // for (RCDevice d : RCDevice.getAllDevices()) {
878 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
879 // for (byte[] portId : d.getAllPortIds() ) {
880 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
881 // }
882 // }
883
884 for (RCLink l : RCLink.getAllLinks()) {
885 putLinkReplicationEvent( new LinkEvent(l.getSrc().dpid, l.getSrc().number, l.getDst().dpid, l.getDst().number));
886 }
887 }
Jonathan Hart062a2e82014-02-03 09:41:57 -0800888}