blob: 7d39ab545e19dece075c9093b6fff420aa8258ef [file] [log] [blame]
Jonathan Hart062a2e82014-02-03 09:41:57 -08001package net.onrc.onos.ofcontroller.networkgraph;
2
Yuta HIGUCHI1c700102014-02-12 16:30:52 -08003import java.net.InetAddress;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08004import java.util.ArrayList;
5import java.util.HashSet;
6import java.util.List;
7import java.util.Set;
8
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -08009import net.onrc.onos.datastore.topology.RCLink;
Jonathan Hart062a2e82014-02-03 09:41:57 -080010import net.onrc.onos.datastore.topology.RCPort;
11import net.onrc.onos.datastore.topology.RCSwitch;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080012import net.onrc.onos.ofcontroller.networkgraph.PortEvent.SwitchPort;
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080013import net.onrc.onos.ofcontroller.util.Dpid;
Jonathan Hart062a2e82014-02-03 09:41:57 -080014
15import org.slf4j.Logger;
16import org.slf4j.LoggerFactory;
17
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080018/**
19 * The "NB" read-only Network Map.
20 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080021 * - Maintain Invariant/Relationships between Topology Objects.
22 *
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080023 * TODO To be synchronized based on TopologyEvent Notification.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080024 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080025 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080026 * Object must exist before adding sub component(Add Switch -> Port).
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080027 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080028 * TODO TBD: This class may delay the requested change to handle event
29 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080030 *
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080031 */
Yuta HIGUCHI928fa682014-02-11 19:07:57 -080032public class NetworkGraphImpl extends AbstractNetworkGraph implements
33 NetworkGraphDiscoveryInterface, NetworkGraphReplicationInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080034
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080035 private static final Logger log = LoggerFactory
36 .getLogger(NetworkGraphImpl.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080037
Jonathan Hart22eb9882014-02-11 15:52:59 -080038 private final NetworkGraphDatastore datastore;
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080039
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080040 public NetworkGraphImpl() {
41 super();
Jonathan Hart22eb9882014-02-11 15:52:59 -080042 datastore = new NetworkGraphDatastore(this);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080043 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080044
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080045 /**
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080046 * Exception to be thrown when Modification to the Network Graph cannot be continued due to broken invariant.
47 *
48 * XXX Should this be checked exception or RuntimeException
49 */
50 public static class BrokenInvariantException extends RuntimeException {
51 private static final long serialVersionUID = 1L;
52
53 public BrokenInvariantException() {
54 super();
55 }
56
57 public BrokenInvariantException(String message) {
58 super(message);
59 }
60 }
Jonathan Hart22eb9882014-02-11 15:52:59 -080061
62 /* ******************************
63 * NetworkGraphDiscoveryInterface methods
64 * ******************************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080065
Jonathan Hart22eb9882014-02-11 15:52:59 -080066 @Override
67 public void putSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -080068 if (prepareForAddSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -080069 datastore.addSwitch(switchEvent);
70 putSwitch(switchEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -080071 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -080072 }
73 // TODO handle invariant violation
74 }
75
76 @Override
77 public void removeSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -080078 if (prepareForRemoveSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -080079 datastore.deactivateSwitch(switchEvent);
80 removeSwitch(switchEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -080081 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -080082 }
83 // TODO handle invariant violation
84 }
85
86 @Override
87 public void putPortEvent(PortEvent portEvent) {
Jonathan Hart4c263272014-02-13 17:41:05 -080088 if (prepareForAddPortEvent(portEvent)) {
89 datastore.addPort(portEvent);
90 putPort(portEvent);
91 // TODO send out notification
92 }
Yuta HIGUCHI75c51ed2014-02-13 17:02:26 -080093 // TODO handle invariant violation
Jonathan Hart22eb9882014-02-11 15:52:59 -080094 }
95
96 @Override
97 public void removePortEvent(PortEvent portEvent) {
Jonathan Hart4c263272014-02-13 17:41:05 -080098 if (prepareForRemovePortEvent(portEvent)) {
99 datastore.deactivatePort(portEvent);
100 removePort(portEvent);
101 // TODO send out notification
102 }
Yuta HIGUCHI75c51ed2014-02-13 17:02:26 -0800103 // TODO handle invariant violation
Jonathan Hart22eb9882014-02-11 15:52:59 -0800104 }
105
106 @Override
107 public void putLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800108 if (prepareForAddLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800109 datastore.addLink(linkEvent);
110 putLink(linkEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800111 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -0800112 }
113 // TODO handle invariant violation
114 }
115
116 @Override
117 public void removeLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800118 if (prepareForRemoveLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800119 datastore.removeLink(linkEvent);
120 removeLink(linkEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800121 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -0800122 }
123 // TODO handle invariant violation
124 }
125
126 @Override
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800127 public void putDeviceEvent(DeviceEvent deviceEvent) {
128 if (prepareForAddDeviceEvent(deviceEvent)) {
129// datastore.addDevice(deviceEvent);
130 // TODO send out notification
131 }
132 // TODO handle invariant violation
133 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800134 }
135
136 @Override
137 public void removeDeviceEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800138 if (prepareForRemoveDeviceEvent(deviceEvent)) {
139// datastore.removeDevice(deviceEvent);
140 // TODO send out notification
141 }
142 // TODO handle invariant violation
143 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800144 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800145
Jonathan Hart22eb9882014-02-11 15:52:59 -0800146 /* *****************
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800147 * Internal methods to maintain invariants of the network graph
Jonathan Hart22eb9882014-02-11 15:52:59 -0800148 * *****************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800149
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800150 /**
151 *
152 * @param swEvt
153 * @return true if ready to accept event.
154 */
155 private boolean prepareForAddSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800156 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800157 // Prep: remove(deactivate) Ports on Switch, which is not on event
158 removePortsNotOnEvent(swEvt);
159 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800160 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800161
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800162 private boolean prepareForRemoveSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800163 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800164 // Prep: remove(deactivate) Ports on Switch, which is not on event
165 // XXX may be remove switch should imply wipe all ports
166 removePortsNotOnEvent(swEvt);
167 return true;
168 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800169
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800170 private void removePortsNotOnEvent(SwitchEvent swEvt) {
171 Switch sw = switches.get( swEvt.getDpid() );
172 if ( sw != null ) {
173 Set<Long> port_noOnEvent = new HashSet<>();
174 for( PortEvent portEvent : swEvt.getPorts()) {
175 port_noOnEvent.add(portEvent.getNumber());
176 }
177 // Existing ports not on event should be removed.
178 // TODO Should batch eventually for performance?
179 for( Port p : sw.getPorts() ) {
180 if ( !port_noOnEvent.contains(p.getNumber()) ) {
181 PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
182 // calling Discovery removePort() API to wipe from DB, etc.
183 removePortEvent(rmEvent);
184 }
185 }
186 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800187 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800188
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800189 private boolean prepareForAddPortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800190 // Parent Switch must exist
191 if ( getSwitch(portEvt.getDpid()) == null) {
192 return false;
193 }
194 // Prep: None
Jonathan Hart22eb9882014-02-11 15:52:59 -0800195 return true;
196 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800197
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800198 private boolean prepareForRemovePortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800199 // Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800200 Switch sw = getSwitch(portEvt.getDpid());
201 if ( sw == null ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800202 return false;
203 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800204 Port port = sw.getPort(portEvt.getNumber());
205 if ( port == null ) {
206 log.debug("Port already removed? {}", portEvt);
207 // let it pass
208 return true;
209 }
210
211 // Prep: Remove Link and Device Attachment
212 for (Device device : port.getDevices()) {
213 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
214 devEvt.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(), port.getNumber()));
215 // calling Discovery API to wipe from DB, etc.
216 removeDeviceEvent(devEvt);
217 }
218 Set<Link> links = new HashSet<>();
219 links.add(port.getOutgoingLink());
220 links.add(port.getIncomingLink());
221 for ( Link link : links) {
222 if (link == null ) {
223 continue;
224 }
225 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
226 // calling Discovery API to wipe from DB, etc.
227 removeLinkEvent(linkEvent);
228 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800229 return true;
230 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800231
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800232 private boolean prepareForAddLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800233 // Src/Dst Switch must exist
234 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
235 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
236 if ( srcSw == null || dstSw == null ) {
237 return false;
238 }
239 // Src/Dst Port must exist
240 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Jonathan Hart4c263272014-02-13 17:41:05 -0800241 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800242 if ( srcPort == null || dstPort == null ) {
243 return false;
244 }
245
246 // Prep: remove Device attachment on both Ports
247 for (Device device : srcPort.getDevices()) {
248 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
249 devEvt.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
250 // calling Discovery API to wipe from DB, etc.
251 removeDeviceEvent(devEvt);
252 }
253 for (Device device : dstPort.getDevices()) {
254 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
255 devEvt.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(), dstPort.getNumber()));
256 // calling Discovery API to wipe from DB, etc.
257 removeDeviceEvent(devEvt);
258 }
259
260 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800261 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800262
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800263 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800264 // Src/Dst Switch must exist
265 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
266 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
267 if ( srcSw == null || dstSw == null ) {
Jonathan Hart4c263272014-02-13 17:41:05 -0800268 log.warn("Rejecting addLink {} because switch doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800269 return false;
270 }
271 // Src/Dst Port must exist
272 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
273 Port dstPort = srcSw.getPort(linkEvt.getDst().number);
274 if ( srcPort == null || dstPort == null ) {
Jonathan Hart4c263272014-02-13 17:41:05 -0800275 log.warn("Rejecting addLink {} because port doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800276 return false;
277 }
Jonathan Hart4c263272014-02-13 17:41:05 -0800278
279 Link link = srcPort.getOutgoingLink();
280
281 if (link == null ||
282 !link.getDestinationPortNumber().equals(linkEvt.getDst().number)
283 || !link.getDestinationSwitchDpid().equals(linkEvt.getDst().dpid)) {
284 log.warn("Rejecting removeLink {} because link doesn't exist", linkEvt);
285 return false;
286 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800287
288 // Prep: None
289 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800290 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800291
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800292 /**
293 *
294 * @param deviceEvt Event will be modified to remove inapplicable attachemntPoints/ipAddress
295 * @return false if this event should be dropped.
296 */
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800297 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800298 boolean preconditionBroken = false;
299 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
300 for ( PortEvent.SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800301 // Attached Ports' Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800302 Switch sw = getSwitch(swp.dpid);
303 if ( sw == null ) {
304 preconditionBroken = true;
305 failedSwitchPort.add(swp);
306 continue;
307 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800308 // Attached Ports must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800309 Port port = sw.getPort(swp.number);
310 if ( port == null ) {
311 preconditionBroken = true;
312 failedSwitchPort.add(swp);
313 continue;
314 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800315 // Attached Ports must not have Link
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800316 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
317 preconditionBroken = true;
318 failedSwitchPort.add(swp);
319 continue;
320 }
321 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800322
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800323 // Rewriting event to exclude failed attachmentPoint
324 // XXX Assumption behind this is that inapplicable device event should
325 // be dropped, not deferred. If we decide to defer Device event,
326 // rewriting can become a problem
327 List<SwitchPort> attachmentPoints = deviceEvt.getAttachmentPoints();
328 attachmentPoints.removeAll(failedSwitchPort);
329 deviceEvt.setAttachmentPoints(attachmentPoints);
330
331 if ( deviceEvt.getAttachmentPoints().isEmpty() && deviceEvt.getIpAddresses().isEmpty() ) {
332 // XXX return false to represent: Nothing left to do for this event. Caller should drop event
333 return false;
334 }
335
336 // Should we return false to tell caller that the event was trimmed?
337 // if ( preconditionBroken ) {
338 // return false;
339 // }
340
341 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800342 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800343
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800344 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800345 // No show stopping precondition?
346 // Prep: none
Jonathan Hart22eb9882014-02-11 15:52:59 -0800347 return true;
348 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800349
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800350 /* ******************************
351 * NetworkGraphReplicationInterface methods
352 * ******************************/
353
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800354 @Override
355 public void putSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800356 // TODO who is in charge of ignoring event triggered by my self?
357 // This method or caller?
358 if (prepareForAddSwitchEvent(switchEvent)) {
359 putSwitch(switchEvent);
360 }
361 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800362 }
363
364 @Override
365 public void removeSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800366 // TODO who is in charge of ignoring event triggered by my self?
367 // This method or caller?
368 if (prepareForRemoveSwitchEvent(switchEvent)) {
369 removeSwitch(switchEvent);
370 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800371 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800372 }
373
374 @Override
375 public void putPortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800376 // TODO who is in charge of ignoring event triggered by my self?
377 // This method or caller?
378 if (prepareForAddPortEvent(portEvent)) {
379 putPort(portEvent);
380 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800381 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800382 }
383
384 @Override
385 public void removePortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800386 // TODO who is in charge of ignoring event triggered by my self?
387 // This method or caller?
388 if (prepareForRemovePortEvent(portEvent)) {
389 removePort(portEvent);
390 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800391 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800392 }
393
394 @Override
395 public void putLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800396 // TODO who is in charge of ignoring event triggered by my self?
397 // This method or caller?
398 if (prepareForAddLinkEvent(linkEvent)) {
399 putLink(linkEvent);
400 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800401 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800402 }
403
404 @Override
405 public void removeLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800406 // TODO who is in charge of ignoring event triggered by my self?
407 // This method or caller?
408 if (prepareForRemoveLinkEvent(linkEvent)) {
409 removeLink(linkEvent);
410 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800411 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800412 }
413
414 @Override
415 public void putDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800416 // TODO who is in charge of ignoring event triggered by my self?
417 // This method or caller?
418 if (prepareForAddDeviceEvent(deviceEvent)) {
419 putDevice(deviceEvent);
420 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800421 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800422 }
423
424 @Override
425 public void removeDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800426 // TODO who is in charge of ignoring event triggered by my self?
427 // This method or caller?
428 if (prepareForRemoveDeviceEvent(deviceEvent)) {
429 removeDevice(deviceEvent);
430 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800431 // TODO Auto-generated method stub
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800432 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800433
434 /* ************************************************
435 * Internal In-memory object mutation methods.
436 * ************************************************/
437
438 void putSwitch(SwitchEvent swEvt) {
439 if (swEvt == null) {
440 throw new IllegalArgumentException("Switch cannot be null");
441 }
442
443 Switch sw = switches.get(swEvt.getDpid());
444
445 if (sw == null) {
446 sw = new SwitchImpl(this, swEvt.getDpid());
447 Switch existing = switches.putIfAbsent(swEvt.getDpid(), sw);
448 if (existing != null) {
449 log.warn(
450 "Concurrent putSwitch not expected. Continuing updating {}",
451 existing);
452 sw = existing;
453 }
454 }
455
456 // Update when more attributes are added to Event object
457 // no attribute to update for now
458
459 // TODO handle child Port event properly for performance
460 for (PortEvent portEvt : swEvt.getPorts() ) {
461 putPort(portEvt);
462 }
463
464 }
465
466 void removeSwitch(SwitchEvent swEvt) {
467 if (swEvt == null) {
468 throw new IllegalArgumentException("Switch cannot be null");
469 }
470
471 // TODO handle child Port event properly for performance
472 for (PortEvent portEvt : swEvt.getPorts() ) {
473 removePort(portEvt);
474 }
475
476 Switch sw = switches.get(swEvt.getDpid());
477
478 if (sw == null) {
479 log.warn("Switch {} already removed, ignoring", swEvt);
480 return;
481 }
482
483 // Sanity check
484 if (!sw.getPorts().isEmpty()) {
485 log.warn(
486 "Ports on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
487 swEvt);
488 // XXX Should we remove Port?
489 }
490 if (!sw.getDevices().isEmpty()) {
491 log.warn(
492 "Devices on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
493 swEvt);
494 // XXX Should we remove Device to Switch relation?
495 }
496 if (!sw.getIncomingLinks().iterator().hasNext()) {
497 log.warn(
498 "IncomingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
499 swEvt);
500 // XXX Should we remove Link?
501 }
502 if (!sw.getOutgoingLinks().iterator().hasNext()) {
503 log.warn(
504 "OutgoingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
505 swEvt);
506 // XXX Should we remove Link?
507 }
508
509 boolean removed = switches.remove(swEvt.getDpid(), sw);
510 if (removed) {
511 log.warn(
512 "Switch instance was replaced concurrently while removing {}. Something is not right.",
513 sw);
514 }
515 }
516
517 void putPort(PortEvent portEvt) {
518 if (portEvt == null) {
519 throw new IllegalArgumentException("Port cannot be null");
520 }
521 Switch sw = switches.get(portEvt.getDpid());
522 if (sw == null) {
523 throw new BrokenInvariantException(String.format(
524 "Switch with dpid %s did not exist.",
525 new Dpid(portEvt.getDpid())));
526 }
527 Port p = sw.getPort(portEvt.getNumber());
528 PortImpl port = null;
529 if (p != null) {
530 port = getPortImpl(p);
531 }
532
533 if (port == null) {
534 port = new PortImpl(this, sw, portEvt.getNumber());
535 }
536
537 // TODO update attributes
538
539 SwitchImpl s = getSwitchImpl(sw);
540 s.addPort(port);
541 }
542
543 void removePort(PortEvent portEvt) {
544 if (portEvt == null) {
545 throw new IllegalArgumentException("Port cannot be null");
546 }
547
548 Switch sw = switches.get(portEvt.getDpid());
549 if (sw == null) {
550 log.warn("Parent Switch for Port {} already removed, ignoring", portEvt);
551 return;
552 }
553
554 Port p = sw.getPort(portEvt.getNumber());
555 if (p == null) {
556 log.warn("Port {} already removed, ignoring", portEvt);
557 return;
558 }
559
560 // check if there is something referring to this Port
561
562 if (!p.getDevices().iterator().hasNext()) {
563 log.warn(
564 "Devices on Port {} should be removed prior to removing Port. Removing Port anyways",
565 portEvt);
566 // XXX Should we remove Device to Port relation?
567 }
568 if (p.getIncomingLink() != null) {
569 log.warn(
570 "IncomingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
571 portEvt);
572 // XXX Should we remove Link?
573 }
574 if (p.getOutgoingLink() != null) {
575 log.warn(
576 "OutgoingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
577 portEvt);
578 // XXX Should we remove Link?
579 }
580
581 // remove Port from Switch
582 SwitchImpl s = getSwitchImpl(sw);
583 s.removePort(p);
584 }
585
586 void putLink(LinkEvent linkEvt) {
587 if (linkEvt == null) {
588 throw new IllegalArgumentException("Link cannot be null");
589 }
590
591 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
592 if (srcSw == null) {
593 throw new BrokenInvariantException(
594 String.format(
595 "Switch with dpid %s did not exist.",
596 new Dpid(linkEvt.getSrc().dpid)));
597 }
598
599 Switch dstSw = switches.get(linkEvt.getDst().dpid);
600 if (dstSw == null) {
601 throw new BrokenInvariantException(
602 String.format(
603 "Switch with dpid %s did not exist.",
604 new Dpid(linkEvt.getDst().dpid)));
605 }
606
607 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
608 if (srcPort == null) {
609 throw new BrokenInvariantException(
610 String.format(
611 "Src Port %s of a Link did not exist.",
612 linkEvt.getSrc() ));
613 }
614
615 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
616 if (dstPort == null) {
617 throw new BrokenInvariantException(
618 String.format(
619 "Dst Port %s of a Link did not exist.",
620 linkEvt.getDst() ));
621 }
622
623 // getting Link instance from destination port incoming Link
624 Link l = dstPort.getIncomingLink();
625 LinkImpl link = null;
626 assert( l == srcPort.getOutgoingLink() );
627 if (l != null) {
628 link = getLinkImpl(l);
629 }
630
631 if (link == null) {
632 link = new LinkImpl(this, srcPort, dstPort);
633 }
634
635
636 PortImpl dstPortMem = getPortImpl(dstPort);
637 PortImpl srcPortMem = getPortImpl(srcPort);
638
639 // Add Link first to avoid further Device addition
640
641 // add Link to Port
642 dstPortMem.setIncomingLink(link);
643 srcPortMem.setOutgoingLink(link);
644
645 // remove Device Pointing to Port if any
646 for(Device d : dstPortMem.getDevices() ) {
647 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, dstPort, linkEvt);
648 DeviceImpl dev = getDeviceImpl(d);
649 dev.removeAttachmentPoint(dstPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800650 // This implies that change is made to Device Object.
651 // sending Device attachment point removed event
652 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
653 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
654 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800655 }
656 dstPortMem.removeAllDevice();
657 for(Device d : srcPortMem.getDevices() ) {
658 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, srcPort, linkEvt);
659 DeviceImpl dev = getDeviceImpl(d);
660 dev.removeAttachmentPoint(srcPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800661 // This implies that change is made to Device Object.
662 // sending Device attachment point removed event
663 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
664 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
665 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800666 }
667 srcPortMem.removeAllDevice();
668
669 }
670
671 void removeLink(LinkEvent linkEvt) {
672 if (linkEvt == null) {
673 throw new IllegalArgumentException("Link cannot be null");
674 }
675
676 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
677 if (srcSw == null) {
678 log.warn("Src Switch for Link {} already removed, ignoring", linkEvt);
679 return;
680 }
681
682 Switch dstSw = switches.get(linkEvt.getDst().dpid);
683 if (dstSw == null) {
684 log.warn("Dst Switch for Link {} already removed, ignoring", linkEvt);
685 return;
686 }
687
688 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
689 if (srcPort == null) {
690 log.warn("Src Port for Link {} already removed, ignoring", linkEvt);
691 return;
692 }
693
694 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
695 if (dstPort == null) {
696 log.warn("Dst Port for Link {} already removed, ignoring", linkEvt);
697 return;
698 }
699
700 Link l = dstPort.getIncomingLink();
701 if ( l == null ) {
702 log.warn("Link {} already removed on destination Port", linkEvt);
703 }
704 l = srcPort.getOutgoingLink();
705 if ( l == null ) {
706 log.warn("Link {} already removed on src Port", linkEvt);
707 }
708
709 getPortImpl(dstPort).setIncomingLink(null);
710 getPortImpl(srcPort).setOutgoingLink(null);
711 }
712
713 // XXX Need to rework Device related
714 void putDevice(DeviceEvent deviceEvt) {
715 if (deviceEvt == null) {
716 throw new IllegalArgumentException("Device cannot be null");
717 }
718
719 Device device = getDeviceByMac(deviceEvt.getMac());
720 if ( device == null ) {
721 device = new DeviceImpl(this, deviceEvt.getMac());
722 Device existing = mac2Device.putIfAbsent(deviceEvt.getMac(), device);
723 if (existing != null) {
724 log.warn(
725 "Concurrent putDevice seems to be in action. Continuing updating {}",
726 existing);
727 device = existing;
728 }
729 }
730 DeviceImpl memDevice = getDeviceImpl(device);
731
732 // for each attachment point
733 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
734 // Attached Ports' Parent Switch must exist
735 Switch sw = getSwitch(swp.dpid);
736 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800737 log.warn("Switch for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800738 continue;
739 }
740 // Attached Ports must exist
741 Port port = sw.getPort(swp.number);
742 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800743 log.warn("Port for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800744 continue;
745 }
746 // Attached Ports must not have Link
747 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
748 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.", port.getOutgoingLink(), port.getIncomingLink());
749 continue;
750 }
751
752 // finally add Device <-> Port on In-memory structure
753 PortImpl memPort = getPortImpl(port);
754 memPort.addDevice(device);
755 memDevice.addAttachmentPoint(port);
756 }
757
758 // for each IP address
759 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
760 // Add Device -> IP
761 memDevice.addIpAddress(ipAddr);
762
763 // Add IP -> Set<Device>
764 boolean updated = false;
765 do {
766 Set<Device> devices = this.addr2Device.get(ipAddr);
767 if ( devices == null ) {
768 devices = new HashSet<>();
769 Set<Device> existing = this.addr2Device.putIfAbsent(ipAddr, devices);
770 if ( existing == null ) {
771 // success
772 updated = true;
773 }
774 } else {
775 Set<Device> updateDevices = new HashSet<>(devices);
776 updateDevices.add(device);
777 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
778 }
779 if (!updated) {
780 log.debug("Collision detected, updating IP to Device mapping retrying.");
781 }
782 } while( !updated );
783 }
784 }
785
786 void removeDevice(DeviceEvent deviceEvt) {
787 if (deviceEvt == null) {
788 throw new IllegalArgumentException("Device cannot be null");
789 }
790
791 Device device = getDeviceByMac(deviceEvt.getMac());
792 if ( device == null ) {
793 log.warn("Device {} already removed, ignoring", deviceEvt);
794 return;
795 }
796 DeviceImpl memDevice = getDeviceImpl(device);
797
798 // for each attachment point
799 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
800 // Attached Ports' Parent Switch must exist
801 Switch sw = getSwitch(swp.dpid);
802 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800803 log.warn("Switch for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800804 continue;
805 }
806 // Attached Ports must exist
807 Port port = sw.getPort(swp.number);
808 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800809 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800810 continue;
811 }
812
813 // finally remove Device <-> Port on In-memory structure
814 PortImpl memPort = getPortImpl(port);
815 memPort.removeDevice(device);
816 memDevice.removeAttachmentPoint(port);
817 }
818
819 // for each IP address
820 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
821 // Remove Device -> IP
822 memDevice.removeIpAddress(ipAddr);
823
824 // Remove IP -> Set<Device>
825 boolean updated = false;
826 do {
827 Set<Device> devices = this.addr2Device.get(ipAddr);
828 if ( devices == null ) {
829 // already empty set, nothing to do
830 updated = true;
831 } else {
832 Set<Device> updateDevices = new HashSet<>(devices);
833 updateDevices.remove(device);
834 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
835 }
836 if (!updated) {
837 log.debug("Collision detected, updating IP to Device mapping retrying.");
838 }
839 } while( !updated );
840 }
841 }
842
843 private SwitchImpl getSwitchImpl(Switch sw) {
844 if (sw instanceof SwitchImpl) {
845 return (SwitchImpl) sw;
846 }
847 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
848 }
849
850 private PortImpl getPortImpl(Port p) {
851 if (p instanceof PortImpl) {
852 return (PortImpl) p;
853 }
854 throw new ClassCastException("PortImpl expected, but found: " + p);
855 }
856
857 private LinkImpl getLinkImpl(Link l) {
858 if (l instanceof LinkImpl) {
859 return (LinkImpl) l;
860 }
861 throw new ClassCastException("LinkImpl expected, but found: " + l);
862 }
863
864 private DeviceImpl getDeviceImpl(Device d) {
865 if (d instanceof DeviceImpl) {
866 return (DeviceImpl) d;
867 }
868 throw new ClassCastException("DeviceImpl expected, but found: " + d);
869 }
870
871 @Deprecated
872 public void loadWholeTopologyFromDB() {
873 // XXX clear everything first?
874
875 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
876 if ( sw.getStatus() != RCSwitch.STATUS.ACTIVE ) {
877 continue;
878 }
879 putSwitchReplicationEvent(new SwitchEvent(sw.getDpid()));
880 }
881
882 for (RCPort p : RCPort.getAllPorts()) {
883 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
884 continue;
885 }
886 putPortReplicationEvent(new PortEvent(p.getDpid(), p.getNumber() ));
887 }
888
889 // TODO Is Device going to be in DB? If so, read from DB.
890 // for (RCDevice d : RCDevice.getAllDevices()) {
891 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
892 // for (byte[] portId : d.getAllPortIds() ) {
893 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
894 // }
895 // }
896
897 for (RCLink l : RCLink.getAllLinks()) {
898 putLinkReplicationEvent( new LinkEvent(l.getSrc().dpid, l.getSrc().number, l.getDst().dpid, l.getDst().number));
899 }
900 }
Jonathan Hart062a2e82014-02-03 09:41:57 -0800901}